Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
24f3444
Add MSSQL support: ODBC driver, pyodbc, sa.false()/sa.true() fix, dev…
spidermila Jun 10, 2026
e10f30f
Make CS_COLLATION dialect-aware (MSSQL uses Czech_100_CI_AS_SC_UTF8)
spidermila Jun 10, 2026
873be6d
Make backup/restore dialect-aware (MSSQL + PostgreSQL)
spidermila Jun 10, 2026
d66034e
Make server_stats digest block dialect-aware (MSSQL + PostgreSQL)
spidermila Jun 10, 2026
f22636a
Make outbox polling dialect-aware: READPAST hint on MSSQL
spidermila Jun 10, 2026
8ff31a9
Add e2e test support for MSSQL
spidermila Jun 10, 2026
61238a2
Address CodeRabbit review: safe identifier quoting, input validation,…
spidermila Jun 10, 2026
ce7183f
Use SQL Server Express edition (free for production)
spidermila Jun 12, 2026
49cb52d
Fix DBCC CHECKIDENT: use string literal instead of repr()
spidermila Jun 12, 2026
4d69bae
Drop PostgreSQL support, MSSQL-only
spidermila Jun 18, 2026
2e67b08
Fix CI: bump cryptography to 49.0.0, fix gpg --batch flag for ODBC in…
spidermila Jun 18, 2026
3297daf
Fix CI: use tee instead of gpg --dearmor for ODBC key install
spidermila Jun 18, 2026
8566ef4
Fix CI: remove conflicting Microsoft APT sources before adding ODBC repo
spidermila Jun 18, 2026
d2cf475
Fix CI: create test DB via Python/pyodbc instead of sqlcmd
spidermila Jun 18, 2026
954b6d9
Document MSSQL one-time bootstrap requirement for production deployment
spidermila Jun 18, 2026
51874ca
Remove PostgreSQL references from docs; keep historical note in PR #381
spidermila Jun 18, 2026
06d58c5
Increase MSSQL stop_grace_period to 60s in prod compose
spidermila Jun 18, 2026
865e907
Fix flaky xdist tests: use NullPool in test app to eliminate connecti…
spidermila Jun 18, 2026
76b696b
Ensure fresh DB session before each test to prevent fixture state lea…
spidermila Jun 18, 2026
9e2dc86
fix: align prod config with Azure SQL deployment, drop Postgres lefto…
spidermila Jun 19, 2026
0646cce
refactor(migrations): squash PostgreSQL history into single MSSQL bas…
spidermila Jun 19, 2026
d040c48
feat(dev): auto-run MSSQL init via one-shot db-init service
spidermila Jun 19, 2026
a0b7748
docs(devops): update for squashed baseline, auto-init, and host ODBC …
spidermila Jun 19, 2026
e8240c8
fix(e2e): apply MSSQL baseline via plain upgrade, drop obsolete stamp…
spidermila Jun 19, 2026
9fefa06
Merge remote-tracking branch 'origin/main' into feat/mssql-support
spidermila Jun 19, 2026
02805c1
refactor(migrations): re-squash baseline after merging main (include …
spidermila Jun 19, 2026
f1d4a9a
ci(migrations): guard against re-squashing the baseline
spidermila Jun 20, 2026
9bcbcf6
docs(changelog): note migration baseline guard
spidermila Jun 22, 2026
8778fb5
Pre-create all xdist worker DBs with RCSI enabled before pytest runs
spidermila Jun 22, 2026
0d1051d
Fix flaky tests: pool_size=2/max_overflow=0 prevents RCSI snapshot ga…
spidermila Jun 22, 2026
673e0e5
Fix CI flakiness: disable RCSI on test DBs, use standard READ COMMITTED
spidermila Jun 22, 2026
abd50cd
Address PR review: fail hard on missing Encrypt, remove dead mssql-in…
spidermila Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,3 @@ docker-compose.prod.yml
render.yaml
deploy.sh
zerver_scp.sh
postgres.conf
db-init/
9 changes: 4 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ FLASK_ENV=development
# Generate with: python -c "import secrets; print(secrets.token_hex(32))"
SECRET_KEY=change-me-generate-a-strong-random-value

# PostgreSQL connection string
# MSSQL connection string
# 'db' is the Docker Compose service name — use this when running inside
# a Docker container (e.g. flask run via docker compose).
# Change to 'localhost' if connecting from the host directly.
DATABASE_URL=postgresql://medcover:devpassword@db:5432/medcover_dev
# PRODUCTION: must include sslmode=require, e.g.:
# DATABASE_URL=postgresql://user:pass@host:5432/dbname?sslmode=require
DATABASE_URL=mssql+pyodbc://medcover:Dev_Password1!@db:1433/medcover_dev?driver=ODBC+Driver+18+for+SQL+Server&Encrypt=no&TrustServerCertificate=yes
# PRODUCTION (Azure SQL with Managed Identity — no password needed):
# DATABASE_URL=mssql+pyodbc://@server.database.windows.net/MedCover?driver=ODBC+Driver+18+for+SQL+Server&Authentication=ActiveDirectoryMsi&Encrypt=yes

# Outbound email (SMTP) is configured through the web UI setup wizard
# and stored encrypted in the database. No SMTP variables are needed here.
Expand Down
12 changes: 5 additions & 7 deletions .env.prod.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ FLASK_ENV=production
# Generate with: python -c "import secrets; print(secrets.token_hex(32))"
SECRET_KEY=change-me-generate-a-strong-random-value

# PostgreSQL — must match the POSTGRES_* values below
DATABASE_URL=postgresql://medcover:<POSTGRES_PASSWORD>@db:5432/medcover_prod

# PostgreSQL container credentials
POSTGRES_DB=medcover_prod
POSTGRES_USER=medcover
POSTGRES_PASSWORD=change-me-use-a-strong-password
# Database — managed Azure SQL service, authenticated passwordlessly via the
# container app's system-assigned managed identity (no credentials stored here).
# Replace <server> with the Azure SQL server name. TLS is enforced (Encrypt=yes).
# See the medcover-infra repo (azure-sql-managed-identity.md) for setup details.
DATABASE_URL=mssql+pyodbc://@<server>.database.windows.net/MedCover?driver=ODBC+Driver+18+for+SQL+Server&Authentication=ActiveDirectoryMsi&Encrypt=yes

# Outbound email (SMTP) is configured through the web UI setup wizard
# and stored encrypted in the database. No SMTP variables are needed here.
Expand Down
59 changes: 48 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,31 @@ jobs:
- name: Run pre-commit hooks
run: pre-commit run --all-files

- name: Guard migration baseline (no re-squash)
run: python scripts/check_migrations.py

test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:17-alpine
mssql:
image: mcr.microsoft.com/mssql/server:2022-latest
env:
POSTGRES_USER: medcover
POSTGRES_PASSWORD: testpassword
POSTGRES_DB: medcover_test
ACCEPT_EULA: "Y"
MSSQL_SA_PASSWORD: "CiPassword123!"
MSSQL_PID: "Express"
MSSQL_COLLATION: "Czech_100_CI_AS_SC_UTF8"
ports:
- 5432:5432
- 1433:1433
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-cmd "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'CiPassword123!' -C -Q 'SELECT 1' -b"
--health-interval 10s
--health-timeout 5s
--health-retries 5
--health-retries 10

env:
DATABASE_URL: postgresql://medcover:testpassword@localhost:5432/medcover_test
TEST_DATABASE_URL: postgresql://medcover:testpassword@localhost:5432/medcover_test
TEST_DATABASE_URL: "mssql+pyodbc://SA:CiPassword123!@localhost:1433/medcover_test?driver=ODBC+Driver+18+for+SQL+Server&Encrypt=no&TrustServerCertificate=yes"
DATABASE_URL: "mssql+pyodbc://SA:CiPassword123!@localhost:1433/medcover_test?driver=ODBC+Driver+18+for+SQL+Server&Encrypt=no&TrustServerCertificate=yes"
FLASK_ENV: testing
SECRET_KEY: ci-test-secret-not-real

Expand All @@ -53,6 +57,39 @@ jobs:
with:
python-version: "3.14"

- name: Install ODBC Driver for SQL Server
run: |
# Remove any existing Microsoft prod sources to avoid Signed-By conflicts
sudo find /etc/apt/sources.list.d/ -name "*.list" -exec grep -l "packages.microsoft.com" {} \; | xargs sudo rm -f
# The runner ships with /usr/share/keyrings/microsoft-prod.gpg — use it
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/ubuntu/$(lsb_release -rs)/prod $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/mssql-release.list
sudo apt-get update -q
sudo ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 unixodbc-dev

- name: Create test database
run: |
pip install pyodbc
python - << 'EOF'
import pyodbc, time
conn_str = "DRIVER={ODBC Driver 18 for SQL Server};SERVER=localhost,1433;DATABASE=master;UID=SA;PWD=CiPassword123!;Encrypt=no;TrustServerCertificate=yes"
for _ in range(30):
try:
conn = pyodbc.connect(conn_str); conn.autocommit = True; break
except Exception:
time.sleep(2)
c = conn.cursor()
# Create base DB + all 4 xdist worker DBs up-front without RCSI.
# Standard READ COMMITTED (no snapshot) guarantees committed rows are
# immediately visible to all connections, eliminating CI snapshot-gap flakiness.
for db_name in ["medcover_test", "medcover_test_gw0", "medcover_test_gw1",
"medcover_test_gw2", "medcover_test_gw3"]:
c.execute(f"IF NOT EXISTS (SELECT 1 FROM sys.databases WHERE name='{db_name}') "
f"CREATE DATABASE [{db_name}] COLLATE Czech_100_CI_AS_SC_UTF8")
print(f"{db_name} ready")
conn.close()
EOF

- name: Install dependencies
run: pip install --require-hashes -r requirements-dev.txt

Expand Down
10 changes: 9 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ repos:
- id: black
exclude: ^migrations/

- repo: local
hooks:
- id: check-migration-baseline
name: Guard migration baseline (no re-squash)
entry: python scripts/check_migrations.py
language: system
pass_filenames: false
files: ^migrations/versions/.*\.py$

- repo: local
hooks:
- id: no-inline-event-handlers
Expand Down Expand Up @@ -79,7 +88,6 @@ repos:
- openpyxl
- alembic
- schedule
- types-psycopg2
args: [--ignore-missing-imports, app/, scheduler/]
pass_filenames: false
always_run: true
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Migration baseline guard (`scripts/check_migrations.py`, wired into CI and pre-commit): fails the build if the squashed Alembic baseline is re-squashed/rewritten (changed root revision id), or if history has multiple roots or heads. Prevents stranding existing databases on deploy. A sanctioned re-baseline procedure is documented in DEVOPS.md.

### Changed
- Database engine switched from PostgreSQL to Microsoft SQL Server (MSSQL 2022 / Azure SQL). PostgreSQL is no longer supported.
- `docker-compose.yml` now uses the MSSQL 2022 Express container instead of PostgreSQL.
- `docker-compose.e2e.yml` updated to use MSSQL.
- `docker-compose.prod.yml` updated to use MSSQL.
- CI pipeline updated to use an MSSQL service container.
- `psycopg2-binary` removed from dependencies; `pyodbc` is the sole DB driver.
- Backup/restore engine updated for MSSQL (IDENTITY_INSERT, DBCC CHECKIDENT, FK constraint handling).
- Test suite migrated to MSSQL; uses a temporary MSSQL container via testcontainers when `TEST_DATABASE_URL` is not pre-set.

## [0.16.0] - 2026-06-09

### Added
Expand Down
Loading
Loading