Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
41a0f33
CHORE: validate Python 3.15 RC2 across PR CI
bewithgaurav Sep 21, 2026
bf20afd
FIX: enforce POSIX native binary hardening
sumitmsft Sep 23, 2026
dd1b21c
FIX: isolate concurrent auth connection mocks
sumitmsft Sep 24, 2026
d3f01a3
Merge branch 'main' into sumitsar/fix-cf041-native-hardening
bewithgaurav Sep 24, 2026
8cf2999
CHORE: validate Python 3.15 with abi3 Rust wheels
bewithgaurav Sep 24, 2026
b9a2b2e
FIX: enforce POSIX native binary hardening
sumitmsft Sep 23, 2026
16729ab
TEST: focus Python 3.15 preview validation
bewithgaurav Sep 24, 2026
5740776
FIX: unblock Python 3.15 validation
bewithgaurav Sep 24, 2026
5d9e7db
FIX: complete Python 3.15 test compatibility
bewithgaurav Sep 24, 2026
78c794f
FIX: adapt error and GC handling for Python 3.15
bewithgaurav Sep 24, 2026
6cf3549
TEST: restore the full PR validation matrix
bewithgaurav Sep 25, 2026
bf75844
Merge PR 810 hardening branch
bewithgaurav Sep 25, 2026
edac63d
Merge branch 'main' into bewithgaurav/python-3.15-validation
bewithgaurav Sep 25, 2026
c7ff914
Merge remote-tracking branch 'origin/main' into bewithgaurav/python-3…
bewithgaurav Oct 1, 2026
8084f02
CHORE: sync Python 3.15 validation with main
bewithgaurav Oct 1, 2026
6942f4a
CHORE: advance hosted Python 3.15 validation to RC3
bewithgaurav Oct 5, 2026
39a06fc
Merge remote-tracking branch 'origin/main' into bewithgaurav/python-3…
bewithgaurav Oct 12, 2026
aab35f4
CHORE: advance Python 3.15 validation to GA
bewithgaurav Oct 12, 2026
242b059
FIX: address Python 3.15 review findings
bewithgaurav Oct 12, 2026
79243f2
FIX: preserve Python 3.10 dependency resolution
bewithgaurav Oct 12, 2026
e062c6d
Merge branch 'main' into bewithgaurav/python-3.15-validation
bewithgaurav Oct 12, 2026
5a106b8
REFACTOR: keep Python 3.15 support scoped
bewithgaurav Oct 12, 2026
2666338
CHORE: refresh universal locks for Python 3.15
bewithgaurav Oct 12, 2026
1c897dc
FIX: keep Python 3.15 review fixes behavioral
bewithgaurav Oct 12, 2026
661e485
FEAT: Build Python 3.15 release wheels (#838)
bewithgaurav Oct 12, 2026
9b89361
FIX: discard Decimal conversion exception context
bewithgaurav Oct 12, 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
25 changes: 23 additions & 2 deletions .github/workflows/refresh-build-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,25 +130,43 @@ jobs:
- name: Linux build
artifact: linux
lock: requirements-build-linux.txt
versions: "3.10 3.11 3.12 3.13 3.14"
versions: "3.10 3.11 3.12 3.13 3.14 3.15"
platforms: "x86_64-manylinux_2_28 aarch64-manylinux_2_28 x86_64-unknown-linux-musl aarch64-unknown-linux-musl"
- name: Linux test
artifact: linux
lock: requirements-test-linux.txt
versions: "3.10 3.11 3.12 3.13 3.14"
platforms: "x86_64-manylinux_2_28 aarch64-manylinux_2_28 x86_64-unknown-linux-musl aarch64-unknown-linux-musl"
- name: Linux test Python 3.15
artifact: linux
lock: requirements-test-linux.txt
versions: "3.15"
platforms: "x86_64-manylinux_2_28 aarch64-manylinux_2_28 x86_64-unknown-linux-musl aarch64-unknown-linux-musl"
allowSourceBuilds: true
- name: macOS
artifact: macos
lock: requirements-build-macos.txt
versions: "3.10 3.11 3.12 3.13 3.14"
platforms: "x86_64-apple-darwin aarch64-apple-darwin"
- name: macOS Python 3.15
artifact: macos
lock: requirements-build-macos.txt
versions: "3.15"
platforms: "x86_64-apple-darwin aarch64-apple-darwin"
allowSourceBuilds: true
# Windows ARM64 stages install build tools into the x64 host
# interpreter before cross-compiling the target extension.
- name: Windows build host
artifact: windows
lock: requirements-build-windows.txt
versions: "3.10 3.11 3.12 3.13 3.14"
platforms: "x86_64-pc-windows-msvc"
- name: Windows build host Python 3.15
artifact: windows
lock: requirements-build-windows.txt
versions: "3.15"
platforms: "x86_64-pc-windows-msvc"
allowSourceBuilds: true
- name: ODBC
artifact: odbc
lock: requirements-build-odbc.txt
Expand All @@ -168,8 +186,11 @@ jobs:
LOCK_FILE: generated-lock/${{ matrix.lock }}
PLATFORMS: ${{ matrix.platforms }}
PYTHON_VERSIONS: ${{ matrix.versions }}
ALLOW_SOURCE_BUILDS: ${{ matrix.allowSourceBuilds || false }}
run: |
set -euo pipefail
binary_args=(--only-binary :all:)
if [ "$ALLOW_SOURCE_BUILDS" = true ]; then binary_args=(); fi
for platform in $PLATFORMS; do
for version in $PYTHON_VERSIONS; do
echo "Validating $LOCK_FILE for Python $version on $platform"
Expand All @@ -179,7 +200,7 @@ jobs:
--target "$RUNNER_TEMP/lock-validation" \
--python-version "$version" \
--python-platform "$platform" \
--only-binary :all: \
"${binary_args[@]}" \
--require-hashes \
--default-index https://pypi.org/simple \
-r "$LOCK_FILE"
Expand Down
52 changes: 30 additions & 22 deletions OneBranchPipelines/build-release-package-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# OneBranch Release Pipeline for mssql-python
# =========================================================================================
# Builds Python wheels for all supported platforms with SDL compliance:
# - Windows: Python 3.10-3.14 (x64 + ARM64)
# - macOS: Python 3.10-3.14 (Universal2 = x86_64 + ARM64 in single binary)
# - Linux: Python 3.10-3.14 on manylinux/musllinux (x86_64 + ARM64)
# - Windows: Python 3.10-3.15 (x64 + ARM64)
# - macOS: Python 3.10-3.15 (Universal2 = x86_64 + ARM64 in single binary)
# - Linux: Python 3.10-3.15 on manylinux/musllinux (x86_64 + ARM64)
#
# Security Features:
# - ESRP code signing (Windows .pyd files only)
Expand Down Expand Up @@ -82,19 +82,19 @@ parameters:
# PLATFORM CONFIGURATIONS
# =========================
# Each platform uses different matrix strategy:
# - Windows: Explicit per-version stages (9 stages for x64/ARM64 combos)
# - macOS: Explicit per-version stages (5 stages for universal2 builds)
# - Windows: Explicit per-version stages (11 stages for x64/ARM64 combos)
# - macOS: Explicit per-version stages (6 stages for universal2 builds)
# - Linux: Per-distro stages, builds ALL Python versions in loop (4 stages)

# Windows Configuration Matrix
# Each entry creates separate stage: Win_py<pyVer>_<arch>
# pyVer format: '310' = Python 3.10, '314' = Python 3.14
# pyVer format: '310' = Python 3.10, '315' = Python 3.15
# arch: 'x64' (Intel/AMD 64-bit) or 'arm64' (ARM64, cross-compiled on x64)
# Note: ARM64 builds use x64 host with ARM64 python.lib for cross-compilation
- name: windowsConfigs
type: object
default:
# x64 builds (5 versions: 3.10-3.14)
# x64 builds (6 versions: 3.10-3.15)
- pyVer: '310'
arch: 'x64'
- pyVer: '311'
Expand All @@ -105,7 +105,9 @@ parameters:
arch: 'x64'
- pyVer: '314'
arch: 'x64'
# ARM64 builds (4 versions: 3.11-3.14)
- pyVer: '315'
arch: 'x64'
Comment thread
bewithgaurav marked this conversation as resolved.
# ARM64 builds (5 versions: 3.11-3.15)
# 3.10 excluded due to limited ARM64 support
- pyVer: '311'
arch: 'arm64'
Expand All @@ -115,23 +117,26 @@ parameters:
arch: 'arm64'
- pyVer: '314'
arch: 'arm64'
- pyVer: '315'
arch: 'arm64'

# macOS Configuration Matrix
# Each entry creates separate stage: MacOS_py<pyVer>
# All builds are Universal2 (x86_64 + ARM64 in single binary)
# pyVer format: '310' = Python 3.10, '314' = Python 3.14
# pyVer format: '310' = Python 3.10, '315' = Python 3.15
- name: macosConfigs
type: object
default:
# 5 versions: 3.10-3.14 (all universal2)
# 6 versions: 3.10-3.15 (all universal2)
- pyVer: '310'
- pyVer: '311'
- pyVer: '312'
- pyVer: '313'
- pyVer: '314'
- pyVer: '315'

# Linux Configuration Matrix
# Each entry creates ONE stage that builds ALL Python versions (3.10-3.14)
# Each entry creates ONE stage that builds ALL Python versions (3.10-3.15)
# tag: 'manylinux' (glibc-based, e.g., Ubuntu/CentOS) or 'musllinux' (musl-based, e.g., Alpine)
# arch: CPU architecture for Docker platform
# platform: Docker platform identifier for multi-arch builds
Expand Down Expand Up @@ -375,17 +380,17 @@ extends:
# =========================
# PIPELINE STAGES
# =========================
# mssql-python: 9 Windows + 5 macOS + 4 Linux + 1 Consolidate = 19 stages
# mssql-python: 11 Windows + 6 macOS + 4 Linux + 1 Consolidate = 22 stages
# mssql-python-odbc: 1 ODBC_BuildAll (single host, all 7 wheels) + 1 ConsolidateOdbc = 2 stages
# Total: 21 stages, always built together. The mssql-python build stages depend on
# Total: 24 stages, always built together. The mssql-python build stages depend on
# ConsolidateOdbc so they install the external ODBC wheel before pytest.
stages:
# =========================
# WINDOWS BUILD STAGES
# =========================
# Strategy: Explicit stage per Python version × architecture
# Total: 9 stages (5 x64 + 4 ARM64)
# Python versions: 3.10-3.14 (x64), 3.11-3.14 (ARM64)
# Total: 11 stages (6 x64 + 5 ARM64)
# Python versions: 3.10-3.15 (x64), 3.11-3.15 (ARM64)
# Each stage:
# 1. Installs Python (UsePythonVersion or NuGet for 3.14)
# 2. Downloads ARM64 python.lib if cross-compiling
Expand Down Expand Up @@ -416,7 +421,7 @@ extends:
# MACOS BUILD STAGES
# =========================
# Strategy: Explicit stage per Python version
# Total: 5 stages (3.10-3.14)
# Total: 6 stages (3.10-3.15)
# All builds are Universal2 (x86_64 + ARM64 in single .so binary)
# Each stage:
# 1. Installs Python via UsePythonVersion@0
Expand Down Expand Up @@ -446,20 +451,20 @@ extends:
# =========================
# Strategy: One stage per distribution × architecture
# Total: 4 stages (manylinux_2_28×2 + musllinux×2)
# Each stage builds ALL Python versions (3.10-3.14) in a loop
# Each stage builds ALL Python versions (3.10-3.15) in a loop
# Distributions:
# - manylinux_2_28: glibc 2.28+ (RHEL 8, Ubuntu 20.04+, etc.) — forward-compatible with newer glibc
# - musllinux: musl-based (Alpine Linux)
# Architectures: x86_64 (AMD/Intel), aarch64 (ARM64)
# Each stage:
# 1. Starts PyPA Docker container (manylinux_2_28 or musllinux_1_2)
# 2. Starts SQL Server Docker container
# 3. For each Python version (cp310-cp314):
# 3. For each Python version (cp310-cp315):
# a. Builds .so native extension
# b. Builds wheel
# c. Installs wheel in isolated directory
# d. Runs pytest against SQL Server
# 4. Publishes artifacts (all 5 wheels)
# 4. Publishes artifacts (all 6 wheels)
# 5. Component Governance + AntiMalware scanning
- ${{ each config in parameters.linuxConfigs }}:
- template: /OneBranchPipelines/stages/build-linux-single-stage.yml@self
Expand All @@ -479,7 +484,7 @@ extends:
# CONSOLIDATE STAGE
# =========================
# Purpose: Collect all artifacts from platform builds into single dist/ folder
# Dependencies: All 18 build stages (9 Windows + 5 macOS + 4 Linux)
# Dependencies: All 21 build stages (11 Windows + 6 macOS + 4 Linux)
# Stages run in parallel, Consolidate waits for ALL to complete
# Outputs:
# - dist/wheels/*.whl (all platform wheels)
Expand All @@ -490,22 +495,25 @@ extends:
- stage: Consolidate
displayName: 'Consolidate All Artifacts'
dependsOn:
# Windows dependencies (9 stages)
# Windows dependencies (11 stages)
- Win_py310_x64
- Win_py311_x64
- Win_py312_x64
- Win_py313_x64
- Win_py314_x64
- Win_py315_x64
- Win_py311_arm64
- Win_py312_arm64
- Win_py313_arm64
- Win_py314_arm64
# macOS dependencies (5 stages)
- Win_py315_arm64
# macOS dependencies (6 stages)
- MacOS_py310
- MacOS_py311
- MacOS_py312
- MacOS_py313
- MacOS_py314
- MacOS_py315
# Linux dependencies (4 stages)
- Linux_manylinux_2_28_x86_64
- Linux_manylinux_2_28_aarch64
Expand Down
14 changes: 7 additions & 7 deletions OneBranchPipelines/jobs/consolidate-artifacts-job.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Consolidate Artifacts Job Template
# Downloads artifacts from all platform build stages and consolidates into single dist/ folder
# Works with individual stage artifacts (18 stages total: 9 Windows + 5 macOS + 4 Linux)
# Each Linux stage builds 5 Python versions (3.10-3.14), resulting in 34 total wheels
# Works with individual stage artifacts (21 stages total: 11 Windows + 6 macOS + 4 Linux)
# Each Linux stage builds 6 Python versions (3.10-3.15), resulting in 41 total wheels
parameters:
- name: oneBranchType
type: string
Expand Down Expand Up @@ -75,17 +75,17 @@ jobs:
echo ""
WHEEL_COUNT=$(ls -1 $(ob_outputDirectory)/dist/*.whl 2>/dev/null | wc -l)
echo "Total wheel count: $WHEEL_COUNT"
echo "Expected: 34 wheels (9 Windows + 5 macOS + 20 Linux)"
echo "Expected: 41 wheels (11 Windows + 6 macOS + 24 Linux)"

# Hard-fail on a wheel-count mismatch (symmetric with the odbc consolidate job).
# A mismatch means a build stage silently produced a partial set (e.g. a missing
# Python version) or the build matrix changed without updating this count.
# Update the expected 34 whenever the Windows/macOS/Linux build matrix changes.
if [ "$WHEEL_COUNT" -ne 34 ]; then
echo "ERROR: Expected 34 wheels but found $WHEEL_COUNT" >&2
# Update the expected 41 whenever the Windows/macOS/Linux build matrix changes.
if [ "$WHEEL_COUNT" -ne 41 ]; then
echo "ERROR: Expected 41 wheels but found $WHEEL_COUNT" >&2
exit 1
else
echo "SUCCESS: All 34 wheels consolidated!"
echo "SUCCESS: All 41 wheels consolidated!"
fi
displayName: 'Consolidate wheels from all platforms'

Expand Down
8 changes: 4 additions & 4 deletions OneBranchPipelines/stages/build-linux-single-stage.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Linux Single Configuration Stage Template
# Builds Python wheels for a specific Linux distribution and architecture
# Builds for Python 3.10, 3.11, 3.12, 3.13, 3.14 within single job
# Builds for Python 3.10, 3.11, 3.12, 3.13, 3.14, 3.15 within single job
# Tests each wheel after building with isolated pytest execution
parameters:
# Stage identifier (e.g., 'Linux_manylinux_2_28_x86_64')
Expand Down Expand Up @@ -256,14 +256,14 @@ stages:
ls -1 "$(Build.SourcesDirectory)/odbc_wheels"/*.whl
displayName: 'Flatten ODBC wheels for pip find-links'

# Build wheels for all Python versions (3.10-3.14) and test each one
# Build wheels for all Python versions (3.10-3.15) and test each one
- script: |
set -euo pipefail
if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then SHELL_EXE=bash; else SHELL_EXE=sh; fi
docker exec build-$(LINUX_TAG)-$(ARCH) $SHELL_EXE -lc 'mkdir -p /workspace/dist'

# Loop through all Python versions: build wheel -> test wheel -> repeat
for PYBIN in cp310 cp311 cp312 cp313 cp314; do
for PYBIN in cp310 cp311 cp312 cp313 cp314 cp315; do
echo ""
echo "====================================================="
echo "Building and testing $PYBIN on $(LINUX_TAG)/$(ARCH)"
Expand Down Expand Up @@ -440,7 +440,7 @@ stages:
echo "====================================================="
echo "✓ All Python versions built and tested successfully!"
echo "====================================================="
displayName: 'Build and test wheels for Python 3.10-3.14'
displayName: 'Build and test wheels for Python 3.10-3.15'
env:
DB_PASSWORD: $(DB_PASSWORD)

Expand Down
1 change: 1 addition & 0 deletions OneBranchPipelines/stages/build-windows-single-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ stages:
"3.12" { "3.12.7" }
"3.13" { "3.13.0" }
"3.14" { "3.14.0" }
"3.15" { "3.15.0" }
}

$nugetUrl = "https://www.nuget.org/api/v2/package/pythonarm64/$nugetVersion"
Expand Down
31 changes: 30 additions & 1 deletion eng/pipelines/pr-validation-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ jobs:
LocalDB_Python314:
sqlVersion: 'LocalDB'
pythonVersion: '3.14'
LocalDB_Python315:
sqlVersion: 'LocalDB'
pythonVersion: '3.15'

steps:
- checkout: self
Expand All @@ -74,6 +77,7 @@ jobs:
inputs:
versionSpec: '$(pythonVersion)'
addToPath: true
allowUnstable: true
githubToken: $(GITHUB_TOKEN)
displayName: 'Use Python $(pythonVersion)'

Expand Down Expand Up @@ -582,6 +586,10 @@ jobs:
sqlServerImage: 'mcr.microsoft.com/mssql/server:2025-latest'
sqlVersion: 'SQL2025'
pythonVersion: '3.14'
SQL2025_Python315:
sqlServerImage: 'mcr.microsoft.com/mssql/server:2025-latest'
sqlVersion: 'SQL2025'
pythonVersion: '3.15'

steps:
- checkout: self
Expand All @@ -591,6 +599,7 @@ jobs:
inputs:
versionSpec: '$(pythonVersion)'
addToPath: true
allowUnstable: true
displayName: 'Use Python $(pythonVersion) on macOS'

- task: Cache@2
Expand Down Expand Up @@ -768,6 +777,11 @@ jobs:
distroName: 'Debian-SQL2025'
sqlServerImage: 'mcr.microsoft.com/mssql/server:2025-latest'
useAzureSQL: 'false'
Debian_Python315:
dockerImage: 'python:3.15.0rc3-bookworm'
distroName: 'Debian-Python315'
sqlServerImage: 'mcr.microsoft.com/mssql/server:2025-latest'
useAzureSQL: 'false'

steps:
- checkout: self
Expand Down Expand Up @@ -797,7 +811,17 @@ jobs:

- script: |
# Install dependencies in the container
if [ "$(distroName)" = "Ubuntu" ]; then
if [ "$(distroName)" = "Debian-Python315" ]; then
docker exec test-container-$(distroName) bash -c "
set -e
export DEBIAN_FRONTEND=noninteractive
export TZ=UTC
ln -snf /usr/share/zoneinfo/\$TZ /etc/localtime && echo \$TZ > /etc/timezone
apt-get update &&
apt-get install -y cmake curl wget gnupg build-essential &&
python3 --version
Comment thread
bewithgaurav marked this conversation as resolved.
"
elif [ "$(distroName)" = "Ubuntu" ]; then
docker exec test-container-$(distroName) bash -c "
export DEBIAN_FRONTEND=noninteractive
export TZ=UTC
Expand Down Expand Up @@ -866,6 +890,7 @@ jobs:
displayName: 'Install Python dependencies in $(distroName) container'

- script: |
set -e
# Build pybind bindings in the container
PROFILER_BUILD=0
if [ "$(Build.Reason)" = "PullRequest" ] &&
Expand Down Expand Up @@ -1078,6 +1103,10 @@ jobs:
dockerImage: 'python:3.11-bookworm'
distroName: 'Debian'
archName: 'arm64'
Debian_Python315_ARM64:
dockerImage: 'python:3.15.0rc3-bookworm'
distroName: 'Debian-Python315'
archName: 'arm64'

steps:
- script: |
Expand Down
Loading
Loading