Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
cd40975
feat(auth): token-expiry capture and identity-aware pool key (#651, #…
jahnvi480 Jul 3, 2026
e3de108
Identity-aware connection pooling: isolate pools by identity (#651)
jahnvi480 Jul 3, 2026
32236ef
feat(pooling): defer token acquisition to a lazy factory on pool miss…
jahnvi480 Jul 3, 2026
5220262
test: cover lazy token-factory edge cases (#659)
jahnvi480 Jul 3, 2026
d38ca6e
docs+test: reconcile design scope with PR #660 and add cross-identity…
jahnvi480 Jul 3, 2026
29c84f9
refactor(pooling): remove dead code and tidy comments in identity-awa…
jahnvi480 Jul 3, 2026
360d407
chore: remove identity-aware pooling design doc from branch
jahnvi480 Jul 3, 2026
5814ee2
Add silent-first interactive auth and lazy eviction of idle identity …
jahnvi480 Jul 3, 2026
0181b52
Reduce pool eviction contention and document auth/pooling contracts
jahnvi480 Jul 3, 2026
0b5f2dc
Reset eviction-sweep throttle on reconfigure and closePools
jahnvi480 Jul 3, 2026
e285e25
test: cover account-keyed pool identity and warning double-check paths
jahnvi480 Jul 3, 2026
65dd8e4
Merge branch 'main' into jahnvi/identity-aware-pooling
jahnvi480 Jul 6, 2026
b4aed11
fix: isolate pool key for raw access tokens; close pools outside mana…
jahnvi480 Jul 6, 2026
4ba2d4f
Fail closed on token acquisition and harden pooled token refresh/evic…
jahnvi480 Jul 6, 2026
e158e1d
Reset _pools_closed on enable so re-enable re-arms the disable guard
jahnvi480 Jul 6, 2026
5700020
Surface auth-acquisition failures as InterfaceError; document token c…
jahnvi480 Jul 6, 2026
0636c6c
Fail closed on non-binary access token; add adversarial pool-key tests
jahnvi480 Jul 6, 2026
71642a3
Harden token factory and pool reuse
jahnvi480 Jul 6, 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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ EntraID authentication is now fully supported on MacOS and Linux but with certai

The Microsoft mssql_python driver provides built-in support for connection pooling, which helps improve performance and scalability by reusing active database connections instead of creating a new connection for every request. This feature is enabled by default. For more information, refer [Connection Pooling Wiki](https://github.com/microsoft/mssql-python/wiki/Connection#connection-pooling).

> **Interactive / Device-code authentication in multi-user processes:** For `ActiveDirectoryInteractive` and `ActiveDirectoryDeviceCode`, the driver caches one credential instance per authentication type for the lifetime of the process so that pooled reconnects refresh silently instead of re-prompting. As a result, every interactive connection opened in the same process shares that one signed-in account — the first user to authenticate. If your application serves multiple end users from a single process, do **not** rely on interactive/device-code auth to isolate them; instead supply your own per-user token via a token provider so each user's connection is keyed to their own identity.

> **Bring-your-own token (`token_provider` / raw access token):** When you supply your own access token (via a token provider or a raw token in `attrs_before`), managing its lifetime is **your application's responsibility**. The driver stores a pooled connection under the identity that opened it, but it cannot refresh a token it did not mint. If a pooled connection is reused after its token has expired, the reconnect (ODBC's implicit connection resiliency) will fail. Ensure your token provider returns a currently-valid token on every call, and account for token expiry in your own logic. The driver's built-in expiry-aware checkout (refreshing a pooled connection whose token is near expiry) only applies to Managed Identity and interactive/device-code pools, whose tokens the driver can silently re-mint — not to bring-your-own tokens.

> **`DefaultAzureCredential` is not recommended for multi-user pooling:** `ActiveDirectoryDefault` resolves to whatever ambient identity `DefaultAzureCredential` discovers (environment, managed identity, developer sign-in, etc.), which is a single process-wide identity. It is well suited to single-identity services but does **not** distinguish between end users, so pooled connections opened with it are not isolated per user. The driver emits a one-time warning in this case. For genuinely multi-user workloads, use a per-user token provider instead. (You will also see this noted in the emitted log warning.) Because a `DefaultAzureCredential` pool is keyed on the token hash rather than a stable identity, it is also **not** expiry-aware: the driver-acquired token is reused until the connection dies, so it is best suited to short-lived or single-identity use.

### DBAPI v2.0 Compliance

The Microsoft **mssql-python** module is designed to be fully compliant with the DB API 2.0 specification. This ensures that the driver adheres to a standardized interface for database access in Python, providing consistency and reliability across different database systems. Key aspects of DBAPI v2.0 compliance include:
Expand Down
31 changes: 26 additions & 5 deletions generate_codecov.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,19 @@ echo "==================================="

# Cleanup old coverage
rm -f .coverage coverage.xml python-coverage.info cpp-coverage.info total.info
rm -rf htmlcov unified-coverage
rm -f default.profraw default.profdata
rm -rf htmlcov unified-coverage profraw

# Capture one raw profile *per process* so subprocess-based tests count too.
# Several pooling tests (idle eviction, pool-full, orphan return) must run in a
# fresh interpreter because the C++ pool config is locked in via std::call_once;
# they spawn `python -c` workers. With a fixed LLVM_PROFILE_FILE every process
# writes the same default.profraw and the last writer (the main pytest process)
# clobbers the workers, dropping their C++ coverage entirely. Using %p (PID) and
# %m (binary signature) gives each instrumented process its own file, which we
# merge below. Subprocess workers inherit this env var (os.environ.copy()).
mkdir -p "$(pwd)/profraw"
export LLVM_PROFILE_FILE="$(pwd)/profraw/default-%p-%m.profraw"

# Run pytest with Python coverage (XML + HTML output)
python -m pytest -v \
Expand All @@ -57,13 +69,22 @@ echo "==================================="
echo "[STEP 3] Processing C++ coverage (Clang/LLVM)"
echo "==================================="

# Merge raw profile data from pybind runs
if [ ! -f default.profraw ]; then
echo "[ERROR] default.profraw not found. Did you build with -fprofile-instr-generate?"
# Merge raw profile data from every instrumented process (main pytest run plus
# any `python -c` subprocess workers). Each wrote its own profraw/*.profraw via
# the LLVM_PROFILE_FILE pattern set in STEP 2.
shopt -s nullglob
PROFRAW_FILES=(profraw/*.profraw)
# Fallback: pick up a legacy single default.profraw if one exists in CWD.
if [ -f default.profraw ]; then
PROFRAW_FILES+=(default.profraw)
fi
if [ ${#PROFRAW_FILES[@]} -eq 0 ]; then
echo "[ERROR] No .profraw files found. Did you build with -fprofile-instr-generate?"
exit 1
fi

llvm-profdata merge -sparse default.profraw -o default.profdata
echo "[INFO] Merging ${#PROFRAW_FILES[@]} raw profile file(s)"
llvm-profdata merge -sparse "${PROFRAW_FILES[@]}" -o default.profdata

# Find the pybind .so file (Linux build)
PYBIND_SO=$(find mssql_python -name "*.so" | head -n 1)
Expand Down
Loading
Loading