From 1bf0125991bf09ef35bf55dd27b1bca6958c5c06 Mon Sep 17 00:00:00 2001 From: Gros Frumos Date: Mon, 16 Mar 2026 20:58:44 +0200 Subject: [PATCH] =?UTF-8?q?kin:=20KIN-095=20=D0=9F=D1=80=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B8=20=D0=B2?= =?UTF-8?q?=20=D1=81=D1=80=D0=B5=D0=B4=D1=8B=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BE=D0=B2=20=D0=B2=D1=8B=D0=BB=D0=B5=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0=20500=20Int?= =?UTF-8?q?ernal=20Server=20Error=20=D0=B2=20=D0=BC=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?=D0=BB=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- tests/test_kin_biz_007_fernet.py | 61 ++++++++++++++++++++++++++++++++ web/api.py | 4 +++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ae86072..e336fbb 100644 --- a/Makefile +++ b/Makefile @@ -32,5 +32,5 @@ test: cd $(FRONTEND_DIR) && npm run test deploy: build-frontend - python -m pip install -r requirements.txt + python3.11 -m pip install -r requirements.txt $(MAKE) serve diff --git a/tests/test_kin_biz_007_fernet.py b/tests/test_kin_biz_007_fernet.py index 857e6dd..2609bde 100644 --- a/tests/test_kin_biz_007_fernet.py +++ b/tests/test_kin_biz_007_fernet.py @@ -51,6 +51,18 @@ def scan_client(tmp_path): return c, env_id +@pytest.fixture +def env_client(tmp_path): + """TestClient with just a project pre-created. Returns client.""" + import web.api as api_module + api_module.DB_PATH = tmp_path / "env_biz007.db" + from web.api import app + from fastapi.testclient import TestClient + c = TestClient(app) + c.post("/api/projects", json={"id": "envproj", "name": "Env Project", "path": "/env"}) + return c + + # --------------------------------------------------------------------------- # AC1: Roundtrip — _encrypt_auth → _decrypt_auth returns original string # --------------------------------------------------------------------------- @@ -325,3 +337,52 @@ def test_deobfuscate_auth_not_imported_in_web_api(): assert not hasattr(api_mod, "_deobfuscate_auth"), ( "_deobfuscate_auth must not appear in web.api" ) + + +# --------------------------------------------------------------------------- +# AC6 (KIN-095): ModuleNotFoundError for cryptography → 503, not 500 +# --------------------------------------------------------------------------- + +def test_create_environment_returns_503_when_cryptography_not_installed(env_client): + """AC6: POST /environments returns 503 when cryptography package missing (not 500).""" + client = env_client + with patch("core.models._encrypt_auth", side_effect=ModuleNotFoundError("No module named 'cryptography'")): + r = client.post("/api/projects/envproj/environments", json={ + "name": "creds-env", "host": "10.0.0.20", "username": "root", + "auth_type": "password", "auth_value": "secret", + }) + assert r.status_code == 503, ( + f"create_environment must return 503 when cryptography is missing, got {r.status_code}: {r.text}" + ) + assert "cryptography" in r.json()["detail"].lower() + + +def test_create_environment_returns_503_not_500_for_missing_cryptography(env_client): + """AC6: 500 must NOT be returned when cryptography package is absent.""" + client = env_client + with patch("core.models._encrypt_auth", side_effect=ModuleNotFoundError("No module named 'cryptography'")): + r = client.post("/api/projects/envproj/environments", json={ + "name": "creds-env2", "host": "10.0.0.21", "username": "root", + "auth_value": "secret2", + }) + assert r.status_code != 500, "Missing cryptography must produce 503, not 500" + + +def test_patch_environment_returns_503_when_cryptography_not_installed(env_client): + """AC6: PATCH /environments/{id} returns 503 when cryptography package missing.""" + client = env_client + # Create env without auth_value so no encryption at create time + r = client.post("/api/projects/envproj/environments", json={ + "name": "patch-env", "host": "10.0.0.22", "username": "root", + }) + assert r.status_code == 201, f"Setup failed: {r.text}" + env_id = r.json()["id"] + + with patch("core.models._encrypt_auth", side_effect=ModuleNotFoundError("No module named 'cryptography'")): + r = client.patch(f"/api/projects/envproj/environments/{env_id}", json={ + "auth_value": "new_secret", + }) + assert r.status_code == 503, ( + f"patch_environment must return 503 when cryptography is missing, got {r.status_code}: {r.text}" + ) + assert "cryptography" in r.json()["detail"].lower() diff --git a/web/api.py b/web/api.py index a6221f5..79218b1 100644 --- a/web/api.py +++ b/web/api.py @@ -1170,6 +1170,8 @@ def create_environment(project_id: str, body: EnvironmentCreate): raise HTTPException(409, f"Environment '{body.name}' already exists for this project") if "KIN_SECRET_KEY" in str(e): raise HTTPException(503, "Server misconfiguration: KIN_SECRET_KEY is not set. Contact admin.") + if isinstance(e, ModuleNotFoundError) or "cryptography" in str(e) or "No module named" in str(e): + raise HTTPException(503, "Server misconfiguration: cryptography package not installed. Run: python3.11 -m pip install cryptography") raise HTTPException(500, str(e)) scan_task_id = None if body.is_installed: @@ -1237,6 +1239,8 @@ def patch_environment(project_id: str, env_id: int, body: EnvironmentPatch): raise HTTPException(409, f"Environment name already exists for this project") if "KIN_SECRET_KEY" in str(e): raise HTTPException(503, "Server misconfiguration: KIN_SECRET_KEY is not set. Contact admin.") + if isinstance(e, ModuleNotFoundError) or "cryptography" in str(e) or "No module named" in str(e): + raise HTTPException(503, "Server misconfiguration: cryptography package not installed. Run: python3.11 -m pip install cryptography") raise HTTPException(500, str(e)) scan_task_id = None