Alembic construit le moteur directement, sans passer par le fichier ini
build / Garde-fou (pull_request) Successful in 9m29s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m44s
build / Garde-fou (push) Successful in 9m31s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m8s
build / Garde-fou (pull_request) Successful in 9m29s
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (pull_request) Skipped
build / Images Harbor (web, Dockerfile) (pull_request) Skipped
build / Images Harbor (catalog-sync, Dockerfile.catalog-sync) (push) Successful in 9m44s
build / Garde-fou (push) Successful in 9m31s
build / Images Harbor (web, Dockerfile) (push) Successful in 13m8s
This commit is contained in:
1 parent
5659c32b66
commit
6c602c97ad
3 files changed
+43
-11
No files matched your search
+5
-1
@@ -36,7 +36,11 @@ Et enfin la revue humaine, qui ne s'automatise pas :
|
||||
documentée ?
|
||||
- une valeur venant de l'utilisateur peut-elle contenir un caractère qui casse le format où
|
||||
on l'insère ? Point-virgule pour le CLAPI, `@` et `:` pour une URL de connexion, guillemet
|
||||
simple pour le shell. Trois incidents sur ce seul motif.
|
||||
simple pour le shell, `%` pour un fichier ini lu par configparser. **Quatre** incidents sur
|
||||
ce seul motif — c'est le premier endroit où regarder.
|
||||
- une valeur déjà encodée traverse-t-elle un second format qui réinterprète son encodage ?
|
||||
C'est la variante du piège précédent : `%40` est correct dans une URL, et devient une
|
||||
interpolation dans un ini.
|
||||
- ce qui est écrit en base a-t-il traversé `strip_secrets` ?
|
||||
|
||||
## Nommage
|
||||
|
||||
+6
-10
@@ -11,7 +11,7 @@ import os
|
||||
import sys
|
||||
|
||||
from alembic import context
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
from sqlalchemy import create_engine, pool
|
||||
|
||||
sys.path.insert(0, os.getcwd())
|
||||
|
||||
@@ -19,15 +19,15 @@ from enclume.config import Config
|
||||
from enclume.db import Base
|
||||
|
||||
config = context.config
|
||||
# Une seule source de verite pour l'URL : celle de l'application, qui sait
|
||||
# assembler les elements separes et encoder le mot de passe.
|
||||
config.set_main_option("sqlalchemy.url", Config.SQLALCHEMY_DATABASE_URI)
|
||||
# L'URL n'est jamais passee par le fichier ini : configparser y verrait des
|
||||
# interpolations, et un mot de passe encode contient des %.
|
||||
URL = Config.SQLALCHEMY_DATABASE_URI
|
||||
target_metadata = Base.metadata
|
||||
|
||||
|
||||
def run_migrations_offline() -> None:
|
||||
context.configure(
|
||||
url=config.get_main_option("sqlalchemy.url"),
|
||||
url=URL,
|
||||
target_metadata=target_metadata,
|
||||
literal_binds=True,
|
||||
dialect_opts={"paramstyle": "named"},
|
||||
@@ -37,11 +37,7 @@ def run_migrations_offline() -> None:
|
||||
|
||||
|
||||
def run_migrations_online() -> None:
|
||||
connectable = engine_from_config(
|
||||
config.get_section(config.config_ini_section, {}),
|
||||
prefix="sqlalchemy.",
|
||||
poolclass=pool.NullPool,
|
||||
)
|
||||
connectable = create_engine(URL, poolclass=pool.NullPool)
|
||||
with connectable.connect() as connection:
|
||||
context.configure(connection=connection, target_metadata=target_metadata)
|
||||
with context.begin_transaction():
|
||||
|
||||
@@ -7,6 +7,7 @@ ici, et la CI reste sans service externe.
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
@@ -388,3 +389,34 @@ def test_les_entetes_du_proxy_sont_honores(app_oidc):
|
||||
headers={"X-Forwarded-Proto": "https", "X-Forwarded-Host": "enclume.example"},
|
||||
)
|
||||
assert vu["url"] == "https://enclume.example/"
|
||||
|
||||
|
||||
def test_alembic_supporte_un_mot_de_passe_encode():
|
||||
"""Un mot de passe contenant @ devient %40 une fois encode ; Alembic ne doit
|
||||
pas y voir une interpolation configparser. On lance la vraie commande."""
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
environnement = {
|
||||
**os.environ,
|
||||
"ENCLUME_DB_HOTE": "hote-inexistant.invalid",
|
||||
"ENCLUME_DB_MOTDEPASSE": "G00d-P@ssw0rd",
|
||||
"PATH": os.environ.get("PATH", ""),
|
||||
}
|
||||
environnement.pop("ENCLUME_DATABASE_URL", None)
|
||||
|
||||
resultat = subprocess.run(
|
||||
[sys.executable, "-m", "alembic", "upgrade", "head"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=environnement,
|
||||
timeout=60,
|
||||
)
|
||||
sortie = resultat.stdout + resultat.stderr
|
||||
# Le point verifie : l'URL a ete lue sans etre prise pour un motif
|
||||
# d'interpolation. L'echec qui suit porte sur la connexion elle-meme.
|
||||
assert "invalid interpolation" not in sortie, sortie[-800:]
|
||||
assert any(
|
||||
marque in sortie
|
||||
for marque in ("OperationalError", "could not translate", "Name or service not known")
|
||||
), sortie[-800:]
|
||||
Reference in new issue
Block a user