Files
ObsiGate/tests/test_ci_workflow.py
T
bruno 7dfe26c83d
CI / lint (push) Failing after 1m50s
CI / test (push) Skipped
CI / build (push) Skipped
CI / e2e (push) Skipped
CI / security (push) Successful in 1m37s
fix: CI security — echo pip-audit sans dièse (runner Act) BUG-083
2026-09-27 09:37:34 -04:00

79 lines
2.9 KiB
Python

"""Garde-fous du workflow CI Gitea (BUG-082, BUG-083).
Sans dépendance (pas de PyYAML) : analyse ligne à ligne de
`.gitea/workflows/ci.yml`, suffisante pour les conventions de ce fichier.
"""
from __future__ import annotations
import re
from pathlib import Path
CI_YML = Path(__file__).resolve().parent.parent / ".gitea" / "workflows" / "ci.yml"
def _run_bodies() -> list[tuple[int, str]]:
"""Toutes les lignes shell de chaque bloc `run:` → [(n° ligne, code)]."""
lines = CI_YML.read_text(encoding="utf-8").splitlines()
bodies: list[tuple[int, str]] = []
i = 0
while i < len(lines):
m = re.match(r"^(\s*)run:(?:\s*\|\s*)?$", lines[i])
inline = re.match(r"^(\s*)run:\s+(\S.*)$", lines[i])
if m:
base = len(m.group(1))
i += 1
while i < len(lines):
cur = lines[i]
if not cur.strip():
i += 1
continue
if len(cur) - len(cur.lstrip()) <= base:
break
bodies.append((i + 1, cur.strip()))
i += 1
elif inline:
bodies.append((i + 1, inline.group(2).strip()))
i += 1
else:
i += 1
return bodies
class TestRunnerProofScripts:
def test_no_hash_inside_run_bodies(self):
"""BUG-083 : aucun `#` dans le code shell des `run:`.
Le runner Gitea Act tronque naïvement au premier `#` (même entre
guillemets) : `echo "... see #87)"` devenait une citation non
fermée → `unexpected EOF while looking for matching '"'` (job
`security` rouge). Les lignes-commentaires shell (`# ...`) restent
autorisées : leur troncature est sémantiquement neutre.
"""
offenders = [
f"L{n}: {code}"
for n, code in _run_bodies()
if not code.startswith("#") and "#" in code
]
assert not offenders, (
"BUG-083 : `#` interdit dans le code des `run:` "
f"(tronqué par le runner) :\n" + "\n".join(offenders)
)
class TestUploadInJsdomStep:
def test_upload_runs_with_jsdom_available(self):
"""BUG-082 : `upload.test.mjs` (import statique `jsdom`) ne tourne
que dans l'étape JSDOM, où `tests/frontend/node_modules` existe."""
text = CI_YML.read_text(encoding="utf-8")
assert "Frontend JSDOM tests" in text
root_part, jsdom_part = text.split("Frontend JSDOM tests", 1)
root_steps = root_part.split("Frontend unit tests", 1)[1]
assert "upload.test" not in root_steps, (
"BUG-082 : `upload.test.mjs` ne doit pas tourner dans l'étape "
"racine (jsdom indisponible)"
)
assert jsdom_part.count("node upload.test.mjs") >= 2, (
"BUG-082 : `node upload.test.mjs` attendu dans les deux branches "
"de l'étape JSDOM"
)