diff --git a/Context.md b/Context.md index 4497c16..cd1a2f0 100644 --- a/Context.md +++ b/Context.md @@ -187,7 +187,8 @@ Get-ChildItem tests\test_*.py | ForEach-Object { "$($_.Name): $((python $_.FullN - Tests run offline against fake HTML pages in `tests/fixtures/` and fake DB connections; they never touch eCW or SQL Server (`test_cdp_browser.py` starts a local Chromium on a debug port). As of 2026-10-27: 71 test - files, **1222 tests** (full run 2026-10-27: 1222/1222) (earlier flaky, each + files, **1224 tests** (full run 2026-10-27: 1222/1222; the 2 Dockerfile + tests since, with test_portal_signin.py 24/24) (earlier flaky, each failed once and passed on rerun: test_verify_no_live_writes, depression_dx_pointer, progress_note_wait — watch them) (about 5 minutes for all of them). @@ -623,8 +624,9 @@ the Portal (restarted 2026-10-26, [portal] terminal tab). History: `git log --oneline`. -Last code commits: `70ba709` (2026-10-27, Portal server mode for Dokploy — -§10), `f99dc17` (2026-10-27, Portal roles Super Admin / +Last code commits: `cc3a01a` (2026-10-27, Portal container on India time — +§10), `69c51d8` (2026-10-27, Dockerfile: libgssapi-krb5-2 for ODBC Driver +18 — §10), `70ba709` (2026-10-27, Portal server mode for Dokploy — §10), `f99dc17` (2026-10-27, Portal roles Super Admin / Admin / Viewer — §2), `61338b4` (2026-10-26, Sign-in page redesign + tab icon — §5), `a436489` (2026-10-26, Portal look: aligned header / footer, 7-day chart, today's reasons, pass rate — §5), `2d4d4fc` @@ -762,8 +764,36 @@ test claim ids — new posts must not (§7). - **Gitea:** one overall snapshot update at the end of a day, when the operator asks (from the clone `D:\ecw-charge-validation`; operator pushes; 2026-10-26: `ba15a57` → `120fd68`). -- **Portal for the client — Gitea + Dokploy (asked 2026-10-23; server - mode built 2026-10-27 `70ba709`, not deployed yet).** `Dockerfile` +- **Portal for the client — Gitea + Dokploy (asked 2026-10-23; LIVE on + Dokploy 2026-10-27, `cc3a01a`, Ecare network only).** URL + `http://10.200.0.15:8085` (Dokploy project Ecw_ChargeValidation → + production → app **Portal**; port 8085 → 8000). The operator signed in + there as Super Admin; Dashboard, Users, Sign-ins work. How it got there: + - **Source = Drop (zip upload), not Git:** Dokploy cannot clone from + Gitea (`server certificate verification failed`, Traefik's self-signed + cert); Gitea has no internal http port and no SSH; the operator cannot + open Dokploy Settings → Git Providers; the OTS-Team Gitea account does + not see `automation-tools`. So: `git archive --format=zip HEAD + Dockerfile requirements-portal.txt src web` → `D:\ecw-portal-deploy\ + portal-.zip` → app → General → Provider → **Drop** → select → + the **Deploy under the drop box** (the top Deploy / Reload rebuilds the + last upload). Long term: ask the Dokploy admin for a Gitea provider. + - **DB:** the SQL Server is on the operator's PC (`MECARE331` = + 10.50.2.131), instance TCP port 58468 (dynamic — a SQL restart may move + it; set a static port later). SQL login **`cv_portal`** (made in SSMS + 2026-10-27: db_datareader + INSERT/UPDATE `CV_PortalUser`, INSERT + `CV_PortalSignIn`); its password only in Dokploy's env + (`RESULTS_DB_CONN`), never here or in chat. The Portal works only while + that PC is on. + - **Fixes found live:** `69c51d8` the image needs `libgssapi-krb5-2` by + name (autoremove took it; ODBC Driver 18 "Can't open lib ... file not + found"); `cc3a01a` `TZ=Asia/Kolkata` + `tzdata` (the server is UTC: a + 15:45 IST Sign-in read 10:15; three such rows stay in CV_PortalSignIn + from 2026-10-27 ~15:45). Errors seen: `SQLSTATE 01000` = driver not + loading; `28000` = login missing / wrong password. + - Sessions are in memory: every Deploy / Reload signs everyone out. + - For the client: needs a public HTTPS URL (or VPN) from IT, and the DB + off a desktop PC. `Dockerfile` (python 3.13-slim + ODBC Driver 18, copies only `src/` + `web/`, `requirements-portal.txt`); env in Dokploy, never in Git: `RESULTS_DB_CONN` (a SQL login; a Linux container cannot use diff --git a/Dockerfile b/Dockerfile index dd3da58..63b8d8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,8 @@ # and PORTAL_URLS in Dokploy's environment — never in Git (.env.example). FROM python:3.13-slim-bookworm -# Microsoft ODBC Driver 18 for SQL Server, for pyodbc. +# Microsoft ODBC Driver 18 for SQL Server, for pyodbc. libgssapi-krb5-2 by +# name: the driver needs it, and autoremove took it with curl otherwise. RUN apt-get update \ && apt-get install -y --no-install-recommends curl gnupg ca-certificates \ && curl -fsSL https://packages.microsoft.com/keys/microsoft.asc \ @@ -12,7 +13,7 @@ RUN apt-get update \ && curl -fsSL https://packages.microsoft.com/config/debian/12/prod.list \ -o /etc/apt/sources.list.d/mssql-release.list \ && apt-get update \ - && ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 \ + && ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 libgssapi-krb5-2 tzdata \ && apt-get purge -y curl gnupg && apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* @@ -24,7 +25,8 @@ COPY web ./web RUN useradd --create-home portal USER portal -ENV PORTAL_SERVER=1 PYTHONUNBUFFERED=1 +# India time, like the bot's rows: Sign-ins and "today" in IST, not UTC. +ENV PORTAL_SERVER=1 PYTHONUNBUFFERED=1 TZ=Asia/Kolkata EXPOSE 8000 CMD ["python", "-m", "uvicorn", "web.app:app", "--host", "0.0.0.0", \ "--port", "8000", "--proxy-headers", "--forwarded-allow-ips", "*"] diff --git a/tests/test_portal_signin.py b/tests/test_portal_signin.py index b5a04c2..53902ce 100644 --- a/tests/test_portal_signin.py +++ b/tests/test_portal_signin.py @@ -378,6 +378,30 @@ def the_portal_url_gives_the_hosts_origins_and_a_secure_cookie(): assert "; secure" in r.headers["set-cookie"].lower(), r.headers +@case +def the_container_keeps_the_odbc_drivers_kerberos_library(): + """Dokploy, 2026-10-27: autoremove took libgssapi-krb5-2 with curl, so + ODBC Driver 18 could not load ("Can't open lib ... file not found").""" + docker = (pathlib.Path(__file__).resolve().parent.parent + / "Dockerfile").read_text(encoding="utf-8") + line = next(l for l in docker.splitlines() if "msodbcsql18" in l + and "install" in l) + assert "libgssapi-krb5-2" in line, line + + +@case +def the_container_keeps_india_time(): + """Dokploy, 2026-10-27: the server clock is UTC, so a Sign-in at 15:45 + IST was recorded 10:15 and "today" would turn at 18:30 IST. The bot's + rows are IST; the Portal must be too.""" + docker = (pathlib.Path(__file__).resolve().parent.parent + / "Dockerfile").read_text(encoding="utf-8") + assert "TZ=Asia/Kolkata" in docker + line = next(l for l in docker.splitlines() if "msodbcsql18" in l + and "install" in l) + assert "tzdata" in line, line + + @case def no_signed_in_page_carries_an_inline_style(): app, _, _ = _portal()