GRM-32: fix: security, dead code, idempotence, and documentation cleanup

This commit is contained in:
emil
2026-06-21 00:14:31 +00:00
parent a676adb025
commit 1717d55013
20 changed files with 351 additions and 476 deletions
+8 -7
View File
@@ -1,18 +1,19 @@
#!/usr/bin/env bash
# Run all molecule scenarios on all supported OS platforms.
# Used by `make molecule-all`. Sequential — CI uses parallel matrix instead.
# Platform list is sourced from scripts/distribute_molecule.py to avoid duplication.
set -euo pipefail
MOLECULE_BIN="$(realpath "${BIN:-.venv/bin}/molecule")"
ROLE_DIR="$(cd "$(dirname "$0")/.." && pwd)/ansible/roles/gitea-runner"
SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
for p in \
ubuntu-2204:geerlingguy/docker-ubuntu2204-ansible:latest:/lib/systemd/systemd \
ubuntu-2404:geerlingguy/docker-ubuntu2404-ansible:latest:/lib/systemd/systemd \
debian-12:geerlingguy/docker-debian12-ansible:latest:/lib/systemd/systemd \
archlinux:marcstraube/archlinux-ansible:latest:/usr/lib/systemd/systemd
do
IFS=":" read -r name image command <<< "$p"
# Read platforms from distribute_molecule.py (single source of truth)
PLATFORMS_OUTPUT="$("$MOLECULE_BIN" python "${SCRIPTS_DIR}/distribute_molecule.py" --list-platforms 2>/dev/null || \
python3 "${SCRIPTS_DIR}/distribute_molecule.py" --list-platforms)"
for p in $PLATFORMS_OUTPUT; do
IFS="|" read -r name image command <<< "$p"
export MOLECULE_PLATFORM_NAME="$name" MOLECULE_PLATFORM_IMAGE="$image"
if [ -n "$command" ]; then
export MOLECULE_PLATFORM_COMMAND="$command"
-123
View File
@@ -1,123 +0,0 @@
#!/usr/bin/env python3
"""Run molecule (scenario, platform) pairs in parallel and kill on first failure.
Each pair is encoded as ``scenario|platform_name|platform_image|platform_command``.
Subprocesses are started concurrently. If any subprocess exits with a non-zero
status, the remaining subprocesses are terminated and this script exits with 1.
Usage:
python3 scripts/run_molecule_parallel.py \
default|ubuntu-2204|ubuntu:22.04| \
lifecycle|debian-12|debian:12| \
...
"""
from __future__ import annotations
import contextlib
import os
import signal
import subprocess # nosec B404
import sys
from pathlib import Path
import click
from gitea_runner_manager.i18n import _
def run_pair(pair: str, role_dir: Path) -> subprocess.Popen[bytes]:
"""Start a subprocess for a single molecule (scenario, platform) pair."""
scenario, platform_name, platform_image, platform_command = pair.split("|")
env = os.environ.copy()
env["MOLECULE_PLATFORM_NAME"] = platform_name
env["MOLECULE_PLATFORM_IMAGE"] = platform_image
if platform_command:
env["MOLECULE_PLATFORM_COMMAND"] = platform_command
elif "MOLECULE_PLATFORM_COMMAND" in env:
del env["MOLECULE_PLATFORM_COMMAND"]
env["ANSIBLE_ALLOW_BROKEN_CONDITIONALS"] = "true"
env["ANSIBLE_INJECT_INVOCATION"] = "1"
cmd = ["molecule", "test"]
if scenario != "default":
cmd.extend(["-s", scenario])
click.echo(_("Starting: {scenario} on {platform}", scenario=scenario, platform=platform_name))
return subprocess.Popen( # nosec B603
cmd,
cwd=str(role_dir),
env=env,
preexec_fn=os.setsid,
)
@click.command()
@click.argument("pairs", nargs=-1, required=True)
def cli(pairs: tuple[str, ...]) -> None:
"""Run molecule pairs in parallel, stop on first failure."""
repo_root = Path(__file__).resolve().parent.parent
role_dir = repo_root / "ansible" / "roles" / "gitea-runner"
processes: list[subprocess.Popen[bytes]] = []
pair_names: list[str] = []
for pair in pairs:
proc = run_pair(pair, role_dir)
processes.append(proc)
pair_names.append(pair)
first_failure: str | None = None
returncode = 0
while processes:
finished_indices: list[int] = []
for i, proc in enumerate(processes):
ret = proc.poll()
if ret is not None:
finished_indices.append(i)
if ret != 0:
first_failure = pair_names[i]
returncode = ret
if first_failure is not None:
click.echo(
_(
"FAILURE: {pair} exited with code {code}. Stopping remaining tests.",
pair=first_failure,
code=returncode,
)
)
for proc in processes:
if proc.poll() is None:
with contextlib.suppress(ProcessLookupError):
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
# Wait briefly, then SIGKILL survivors
for proc in processes:
try:
proc.wait(timeout=5)
except subprocess.TimeoutExpired:
with contextlib.suppress(ProcessLookupError):
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
proc.wait()
sys.exit(returncode)
if not finished_indices:
# No process finished yet, wait a bit
for proc in processes:
try:
proc.wait(timeout=5)
except subprocess.TimeoutExpired:
pass
continue
# Remove finished processes from the list
for i in sorted(finished_indices, reverse=True):
del processes[i]
del pair_names[i]
click.echo(_("All molecule tests passed."))
sys.exit(0)
if __name__ == "__main__": # pragma: no cover
cli()