name: Test System Utilities on: push: branches: [dev] paths: - 'backend/app/utils/system.py' - 'backend/app/services/**' - 'backend/tests/test_utils_system*.py' - '.github/workflows/test-system-utils.yml' pull_request: branches: [main, dev] paths: - 'backend/app/utils/system.py' - 'backend/app/services/**' - 'backend/tests/test_utils_system*.py' # The mocked `unit-tests` job that used to lead this file was removed: it ran # `pytest tests/test_utils_system.py`, and Backend CI's # `pytest tests -v` already collects that exact file — there is no pytest.ini, # addopts, or collect_ignore narrowing it. What is left here is the part # Backend CI genuinely cannot do: exercise the package-manager detection # against real apt/dnf inside real distro images. jobs: # ────────────────────────────────────────────────────────────────── # Job 1: Integration tests on real distros (no mocks) # ────────────────────────────────────────────────────────────────── integration-tests: name: Integration (${{ matrix.distro }}) runs-on: ubuntu-latest # A wedged apt mirror once held the ubuntu job "in progress" for 2 h, and # Version Bump waits on every sibling — fail fast instead of blocking dev. timeout-minutes: 15 strategy: fail-fast: false matrix: include: - distro: ubuntu image: ubuntu:24.04 expected_manager: apt - distro: debian image: debian:12 expected_manager: apt - distro: fedora image: fedora:41 expected_manager: dnf - distro: rocky image: rockylinux:9 expected_manager: dnf container: image: ${{ matrix.image }} env: DEBIAN_FRONTEND: noninteractive steps: - uses: actions/checkout@v4 - name: Install Python & pytest shell: bash run: | if command -v apt-get >/dev/null 2>&1; then rm -rf /var/lib/apt/lists/* apt-get -o Acquire::Retries=3 -o Acquire::http::Timeout=30 update apt-get -o Acquire::Retries=3 -o Acquire::http::Timeout=30 -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold install -y python3 python3-pip elif command -v dnf >/dev/null 2>&1; then dnf install -y python3 python3-pip elif command -v yum >/dev/null 2>&1; then yum install -y python3 python3-pip fi pip3 install --break-system-packages pytest 2>/dev/null || pip3 install pytest - name: Run integration smoke tests working-directory: backend env: EXPECTED_MANAGER: ${{ matrix.expected_manager }} run: python3 -m pytest tests/test_utils_system_integration.py -v # ────────────────────────────────────────────────────────────────── # Job 2: Audit — grep for raw subprocess patterns in services # ────────────────────────────────────────────────────────────────── audit-raw-patterns: name: Audit Raw Subprocess Patterns runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' # The ratchet (plan 75 §G1). The grep steps below check a hand-listed set # of files for three known-bad patterns; this counts EVERY raw # subprocess call site under backend/app and fails if the total grew. # A grep cannot do this honestly — it also matches comments, docstrings # and `except subprocess.SubprocessError` — so the census is AST-based. - name: Raw subprocess census (ceiling may only go down) working-directory: backend run: python3 tests/raw_subprocess_census.py - name: Check for raw 'sudo systemctl' calls in migrated services run: | MIGRATED_FILES=( backend/app/services/firewall_service.py backend/app/services/security_service.py backend/app/services/python_service.py backend/app/services/deployment_service.py backend/app/services/ftp_service.py backend/app/services/nginx_service.py backend/app/services/php_service.py backend/app/services/ssl_service.py ) EXIT_CODE=0 echo "=== Checking for raw subprocess patterns ===" echo "" # Pattern 1: subprocess.run with 'sudo', 'systemctl' echo "--- Pattern: 'sudo', 'systemctl' ---" for f in "${MIGRATED_FILES[@]}"; do if [ -f "$f" ]; then MATCHES=$(grep -n "'sudo', 'systemctl'" "$f" || true) if [ -n "$MATCHES" ]; then echo "FAIL: $f" echo "$MATCHES" EXIT_CODE=1 fi fi done # Pattern 2: subprocess.run with dpkg echo "" echo "--- Pattern: subprocess.run.*dpkg ---" for f in "${MIGRATED_FILES[@]}"; do if [ -f "$f" ]; then MATCHES=$(grep -n "subprocess\.run.*dpkg" "$f" || true) if [ -n "$MATCHES" ]; then echo "FAIL: $f" echo "$MATCHES" EXIT_CODE=1 fi fi done # Pattern 3: os.path.exists('/usr/bin/apt') echo "" echo "--- Pattern: os.path.exists('/usr/bin/apt') ---" for f in "${MIGRATED_FILES[@]}"; do if [ -f "$f" ]; then MATCHES=$(grep -n "os\.path\.exists.*'/usr/bin/apt'" "$f" || true) if [ -n "$MATCHES" ]; then echo "FAIL: $f" echo "$MATCHES" EXIT_CODE=1 fi fi done echo "" if [ $EXIT_CODE -eq 0 ]; then echo "All migrated files are clean." else echo "Raw subprocess patterns found — see failures above." fi exit $EXIT_CODE