Skip to content

test(cli): skip install.sh tests on Windows runner (#1099)#1101

Merged
muddlebee merged 1 commit intoTracer-Cloud:mainfrom
mayankbharati-ops:fix/1099-skip-install-sh-tests-on-windows
Apr 30, 2026
Merged

test(cli): skip install.sh tests on Windows runner (#1099)#1101
muddlebee merged 1 commit intoTracer-Cloud:mainfrom
mayankbharati-ops:fix/1099-skip-install-sh-tests-on-windows

Conversation

@mayankbharati-ops
Copy link
Copy Markdown
Contributor

Closes #1099.

Root cause

The post-merge test (windows-latest) job on 67dc64d1 (the merge of #1090) is failing with two distinct symptoms in the install.sh test suite added by #1064:

1. tests/cli/test_install_sh_path.py — 12 failures

The helper _run calls subprocess.run(["bash", "-c", script]). On the GitHub Actions windows-latest runner, bash resolves to wsl.exe, and that runner has no installed WSL distribution. Every _run exits with code 1 and the literal message:

Windows Subsystem for Linux has no installed distributions.
You can resolve this by installing a distribution with the instructions below

So none of the asserted rc files (.zshrc, .bashrc, config.fish) ever get written, and assertions like assert zshrc.exists() and assert result.returncode == 0 fail.

2. tests/cli/test_install_sh_resolution.py — module collection error

@pytest.mark.skipif(os.geteuid() == 0, reason="sudo fallback is only meaningful for non-root users")

os.geteuid does not exist on Windows. The decorator condition is evaluated at decorator-application time (i.e. module import), so AttributeError: module 'os' has no attribute 'geteuid' fires before pytest gets a chance to read any markers. The whole module fails to collect.

Why skip rather than fix the test scaffolding

Both files exclusively test install.sh, which is a POSIX shell script driving zsh/bash/fish rc-file behaviour. There's no Windows analogue (the project ships a separate Windows installer / pip install path), so installing WSL or porting the test scaffolding to PowerShell would be busywork. Skipping the module on Windows matches what the codebase actually claims to support.

Changes

# test_install_sh_path.py
pytestmark = pytest.mark.skipif(
    sys.platform == "win32",
    reason="install.sh is POSIX-only; the Windows runner has no usable bash "
           "(resolves to unconfigured WSL), so this module's subprocess-driven "
           "tests cannot run there. See issue #1099.",
)

test_install_sh_resolution.py gets the same pytestmark, plus a defensive replacement of the bare os.geteuid() access:

# Evaluated once at module load. hasattr short-circuits the `and` on
# Windows, so os.geteuid() is never called there — the module imports
# cleanly even before pytest reads ``pytestmark``.
_RUNNING_AS_ROOT = hasattr(os, "geteuid") and os.geteuid() == 0

@pytest.mark.skipif(_RUNNING_AS_ROOT, reason="sudo fallback is only meaningful for non-root users")

Without that defensive guard the module still wouldn't import on Windows, even with pytestmark defined — and pytestmark only kicks in once pytest has collected the module.

Verification

macOS / Linux Windows
Module imports ✅ unchanged ✅ no more AttributeError
Tests run ✅ all 15 pass on local macOS Skipped cleanly with reason text
Existing root-skip ✅ still active on Unix when running as root n/a (whole module skipped)
ruff check / ruff format --check ✅ clean ✅ clean
Full unit suite 4164 / 2 skipped / 1 xfailed (will skip 13 from these modules + still fail count = 0)

Scope

File Change
tests/cli/test_install_sh_path.py +13 / -0 (module-level pytestmark + comment block)
tests/cli/test_install_sh_resolution.py +28 / -1 (pytestmark + defensive _RUNNING_AS_ROOT constant; existing decorator references the new constant)

No production code touched. No test logic changed for the platforms where these tests do run.

cc @muddlebee — this is the post-#1090 Windows CI fix. Both files were added by #1064 and have been failing on Windows since that landed; this PR makes the Windows runner green again without changing any Unix-side behaviour.

…racer-Cloud#1099)

The post-merge ``test (windows-latest)`` job on commit 67dc64d (PR Tracer-Cloud#1090
landing) is failing with two distinct symptoms in the install.sh test
suites added by PR Tracer-Cloud#1064:

1. ``tests/cli/test_install_sh_path.py`` — 12 tests fail because the
   subprocess call ``subprocess.run(["bash", "-c", script])`` resolves
   ``bash`` to ``wsl.exe`` on the GitHub Actions ``windows-latest``
   runner, and that runner has no installed WSL distribution. Every
   ``_run`` call exits 1 with a literal "Windows Subsystem for Linux
   has no installed distributions" message, so none of the asserted
   rc files (``.zshrc``/``.bashrc``/``config.fish``) ever get written.

2. ``tests/cli/test_install_sh_resolution.py`` — module fails to import
   on Windows: the existing
   ``@pytest.mark.skipif(os.geteuid() == 0, reason=...)`` decorator
   evaluates ``os.geteuid()`` at decorator-application time, but
   ``os.geteuid`` does not exist on Windows. ``AttributeError`` fires
   *before* pytest can read any markers, blocking collection of every
   test in the module.

Both files exclusively test ``install.sh``, which is a POSIX shell
script (zsh/bash/fish RC files) with no Windows analogue, so the
correct fix for the Windows runner is to skip them.

Changes:

- ``test_install_sh_path.py``: module-level
  ``pytestmark = pytest.mark.skipif(sys.platform == "win32", ...)``
  with a comment that names the failure mode.

- ``test_install_sh_resolution.py``: same module-level skipif, *and*
  defensively replace ``os.geteuid() == 0`` with
  ``_RUNNING_AS_ROOT = hasattr(os, "geteuid") and os.geteuid() == 0``
  evaluated once at module load. ``hasattr`` short-circuits the ``and``
  on Windows so ``os.geteuid()`` is never called there — the module
  imports cleanly even before pytest reads ``pytestmark``.

No source-checkout behaviour change: skipif is a no-op on macOS/Linux,
and the existing root-only test still skips correctly on those
platforms (verified by running ``pytest tests/cli/test_install_sh_path.py
tests/cli/test_install_sh_resolution.py`` locally — 15 / 15 pass).
Full unit suite: 4164 pass / 2 skipped / 1 xfailed.

Closes Tracer-Cloud#1099.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 30, 2026

Greptile Summary

Adds module-level pytestmark skips to both install.sh test files so the windows-latest CI runner no longer fails when bash resolves to an unconfigured WSL. test_install_sh_resolution.py also replaces the bare os.geteuid() == 0 decorator argument with a hasattr-guarded _RUNNING_AS_ROOT constant, which correctly prevents AttributeError at import time on Windows (before pytestmark can take effect). No production code or Unix-side test behaviour is changed.

Confidence Score: 5/5

Safe to merge — minimal, targeted fix with no production code changes and no Unix-side test regressions.

Both changes are correct: pytestmark is the idiomatic pytest mechanism for module-level skips, and the hasattr short-circuit is necessary and sufficient to prevent the import-time AttributeError. No logic is altered for macOS/Linux. No P0 or P1 findings.

No files require special attention.

Important Files Changed

Filename Overview
tests/cli/test_install_sh_path.py Adds import sys, import pytest, and a module-level pytestmark that skips all 12 tests on win32; no test logic changed.
tests/cli/test_install_sh_resolution.py Adds module-level pytestmark Windows skip and replaces bare os.geteuid() == 0 with a hasattr-guarded _RUNNING_AS_ROOT constant to prevent AttributeError at import time on Windows.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[pytest collects module] --> B{sys.platform == win32?}
    B -- Yes --> C[pytestmark: skip all tests\nin module with reason text]
    B -- No --> D[Evaluate _RUNNING_AS_ROOT\nhasattr guard]
    D --> E{os.geteuid == 0?}
    E -- Yes --> F[skip test_uses_sudo_for_non_writable_system_path_dir]
    E -- No --> G[Run all tests via\nsubprocess bash -c]
    G --> H[Assert rc-file writes\nand return codes]
Loading

Reviews (2): Last reviewed commit: "test(cli): skip install.sh tests on Wind..." | Re-trigger Greptile

@muddlebee
Copy link
Copy Markdown
Collaborator

@mayankbharati-ops I hope only these two were the affected regions?

@muddlebee muddlebee marked this pull request as draft April 30, 2026 07:04
@muddlebee muddlebee marked this pull request as ready for review April 30, 2026 07:04
@muddlebee
Copy link
Copy Markdown
Collaborator

@mayankbharati-ops I just added a custom workflow check(already in main), after your PR. so maintainers can trigger window CI checks during PR only.. have triggered it here, pls see if any more windows issues..

looks like it passed #1102

@muddlebee muddlebee merged commit d09b7c2 into Tracer-Cloud:main Apr 30, 2026
7 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🛸 Aliens watching our repo just upgraded @mayankbharati-ops's threat level to: do not engage — too competent. 👽


👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome.

@muddlebee
Copy link
Copy Markdown
Collaborator

@mayankbharati-ops thanks for the quick fix. window checks green at #1102

@mayankbharati-ops
Copy link
Copy Markdown
Contributor Author

@muddlebee yes — those two were the only affected modules. I just re-audited the test tree to be sure, and PR #1102's now-green Windows checks corroborate it:

Audit results across tests/:

Pattern Hits Files
subprocess.run(["bash"...]) / ["sh"...] / ["zsh"...] / ["fish"...] 2 both fixed in #1101
os.geteuid / os.getuid / os.fork / os.symlink / os.getlogin 1 only test_install_sh_resolution.py (fixed in #1101)
import pwd / import grp / import fcntl / import termios / import resource 0
Hard-coded Unix paths (/tmp/..., /usr/...) actually opened from disk 0 the only /tmp/... references in test_investigate_service_flag.py:86 and test_health_view.py:75 are test-parameter strings the CLI rejects/serializes without touching the filesystem — safe on Windows

So the surface area for Windows-specific test failures was exactly those two files. The "windows test SUCCESS" on #1102 is the empirical confirmation.

Re: the pre-merge Windows trigger — that's a nice addition. With it, this whole regression class would have been caught at PR-review time on #1064 (where these tests landed) instead of post-merge. Glad it's in.

Thanks for the quick merge!

@muddlebee
Copy link
Copy Markdown
Collaborator

@mayankbharati-ops in case you are interested how we added the new ci windows workflows

base PR: #1100
follow up PR: #1103

gitsofaryan pushed a commit to gitsofaryan/opensre that referenced this pull request May 3, 2026
…racer-Cloud#1099) (Tracer-Cloud#1101)

The post-merge ``test (windows-latest)`` job on commit 67dc64d (PR Tracer-Cloud#1090
landing) is failing with two distinct symptoms in the install.sh test
suites added by PR Tracer-Cloud#1064:

1. ``tests/cli/test_install_sh_path.py`` — 12 tests fail because the
   subprocess call ``subprocess.run(["bash", "-c", script])`` resolves
   ``bash`` to ``wsl.exe`` on the GitHub Actions ``windows-latest``
   runner, and that runner has no installed WSL distribution. Every
   ``_run`` call exits 1 with a literal "Windows Subsystem for Linux
   has no installed distributions" message, so none of the asserted
   rc files (``.zshrc``/``.bashrc``/``config.fish``) ever get written.

2. ``tests/cli/test_install_sh_resolution.py`` — module fails to import
   on Windows: the existing
   ``@pytest.mark.skipif(os.geteuid() == 0, reason=...)`` decorator
   evaluates ``os.geteuid()`` at decorator-application time, but
   ``os.geteuid`` does not exist on Windows. ``AttributeError`` fires
   *before* pytest can read any markers, blocking collection of every
   test in the module.

Both files exclusively test ``install.sh``, which is a POSIX shell
script (zsh/bash/fish RC files) with no Windows analogue, so the
correct fix for the Windows runner is to skip them.

Changes:

- ``test_install_sh_path.py``: module-level
  ``pytestmark = pytest.mark.skipif(sys.platform == "win32", ...)``
  with a comment that names the failure mode.

- ``test_install_sh_resolution.py``: same module-level skipif, *and*
  defensively replace ``os.geteuid() == 0`` with
  ``_RUNNING_AS_ROOT = hasattr(os, "geteuid") and os.geteuid() == 0``
  evaluated once at module load. ``hasattr`` short-circuits the ``and``
  on Windows so ``os.geteuid()`` is never called there — the module
  imports cleanly even before pytest reads ``pytestmark``.

No source-checkout behaviour change: skipif is a no-op on macOS/Linux,
and the existing root-only test still skips correctly on those
platforms (verified by running ``pytest tests/cli/test_install_sh_path.py
tests/cli/test_install_sh_resolution.py`` locally — 15 / 15 pass).
Full unit suite: 4164 pass / 2 skipped / 1 xfailed.

Closes Tracer-Cloud#1099.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] : CI failing for opensre tests

2 participants