fix(ops): nginx pointait sur le port du serveur de developpement

STD-06, de l'audit anterieur : "ports et adresses d'ecoute incoherents entre
cinq fichiers". ARCH-007 a unifie les points d'entree Python en vague E/F et
OPS-002 a fait de HOST et PORT des variables en vague H, mais personne n'est
retourne dans app/nginx.conf.

proxy_pass pointait sur 127.0.0.1:5000, qui est le defaut de run.py, le
serveur de developpement. wsgi.py -- ce qui sert reellement la production --
ecoute PORT avec un defaut de 10000. Installer le fichier tel qu'il est
livre donne donc 502 sur chaque page, depuis une configuration qui se lit
comme parfaitement raisonnable et un serveur qui tourne tres bien.

Rien dans le depot ne reliait les deux nombres, donc rien ne pouvait
remarquer qu'ils avaient diverge. Le test est cette relation, ecrite
quelque part qui s'execute. Il couvre aussi les blocs commentes : celui
qu'on decommente dans un an porte le port avec lequel il a ete ecrit.

Le second test garde l'avertissement colle au chemin alias du bloc /static/,
livre avec une valeur devinee et toujours a regler sur le noeud.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
GGThed
2026-08-11 19:37:25 -04:00
co-authored by Claude Opus 5
parent dd8b9671c6
commit 9cedf4a038
2 changed files with 86 additions and 3 deletions
+74
View File
@@ -0,0 +1,74 @@
"""The shipped nginx template, checked against the code it fronts.
STD-06. `app/nginx.conf` proxied to `127.0.0.1:5000` — run.py's development
default — while `wsgi.py`, which is what actually serves production, binds
`PORT` with a default of 10000. Installing the file as shipped therefore
produced 502 Bad Gateway on every page, from a configuration that reads as
entirely reasonable and a server that is running perfectly well.
Nothing in the repository related the two numbers, so nothing could notice
they had diverged. That is what this file is: the relation, written down
somewhere that runs.
It deliberately checks only what can be wrong in a way that breaks the site
silently. The rest of the nginx configuration is the operator's.
"""
import pathlib
import re
import pytest
ROOT = pathlib.Path(__file__).resolve().parent.parent
NGINX_CONF = ROOT / 'app' / 'nginx.conf'
WSGI = ROOT / 'wsgi.py'
@pytest.fixture(scope='module')
def nginx_text():
return NGINX_CONF.read_text(encoding='utf-8')
def _wsgi_default_port():
"""The port wsgi.py binds when PORT is unset."""
match = re.search(r"os\.getenv\(\s*'PORT'\s*,\s*(\d+)\s*\)", WSGI.read_text(encoding='utf-8'))
assert match, 'wsgi.py no longer reads PORT the way this test expects'
return match.group(1)
class TestTheUpstreamPort:
def test_the_wsgi_default_is_findable(self):
"""Premise: if the regex stopped matching, every test below would be
comparing against nothing."""
assert _wsgi_default_port().isdigit()
def test_every_proxy_pass_targets_it(self, nginx_text):
"""Including the commented-out ones. A block someone uncomments a
year from now carries whatever port it was written with."""
expected = _wsgi_default_port()
ports = re.findall(r'proxy_pass\s+http://127\.0\.0\.1:(\d+)', nginx_text)
assert ports, 'no proxy_pass found; this test is no longer checking anything'
assert set(ports) == {expected}, (
f'nginx proxies to {sorted(set(ports))} but wsgi.py binds {expected}. '
f'Installing this file would give 502 on every page.'
)
class TestTheStaticAliasIsStillFlagged:
"""The /static/ alias is shipped with a guessed path, and the HANDOFF
lists it as a node setting. This test does not know the right value —
it makes sure the warning stays next to it."""
def test_the_alias_says_it_must_be_checked(self, nginx_text):
lines = nginx_text.splitlines()
alias_lines = [i for i, line in enumerate(lines) if line.strip().startswith('alias ')]
if not alias_lines:
pytest.skip('no alias directive in this configuration')
for index in alias_lines:
preceding = '\n'.join(lines[max(0, index - 20) : index]).lower()
assert any(word in preceding for word in ('adjust', 'check', 'guess', 'must match')), (
f'line {index + 1}: the alias path is a guess about the deployment '
f'layout; the note saying so must stay with it'
)