Skip to content

FIX: Sign Windows native .pyd binaries with ESRP in official and non-official builds - #709

Open
Saurabh Singh (saurabh500) wants to merge 2 commits into
mainfrom
dev/saurabh/sign-pyd-files
Open

FIX: Sign Windows native .pyd binaries with ESRP in official and non-official builds#709
Saurabh Singh (saurabh500) wants to merge 2 commits into
mainfrom
dev/saurabh/sign-pyd-files

Conversation

@saurabh500

@saurabh500 Saurabh Singh (saurabh500) commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds ESRP Authenticode signing of the compiled Windows native extension (ddbc_bindings.cp<ver>-<arch>.pyd) in the OneBranch release pipeline, so every published wheel contains a signed extension. Signing runs in both Official and NonOfficial pipeline runs.

Because the .pyd is built in a dedicated step before setup.py bdist_wheel packages it, we sign the .pyd in place — no wheel unpack/repack and no RECORD hash regeneration (unlike the maturin-based flow in mssql-rs #100). The signed binary then flows automatically into the .whl, the bindings/windows artifact, and the apiScan copy.

We deliberately scope signing to our specifically-named extension (ddbc_bindings.cp<ver>-<arch>.pyd) rather than a broad *.pyd/*.dll net. The vcredist msvcp140.dll that build.bat copies next to the extension is already Microsoft-signed and is not ours to re-sign, so it is intentionally excluded. The malware-scan, sign, and verify scopes are all driven by the same exact pattern.

Changes

  • OneBranchPipelines/steps/compound-esrp-code-signing-step.yml — reusable native-extension signer: EsrpMalwareScanning@5EsrpCodeSigning@5 (CP-230012, SigntoolSign + SigntoolVerify) → an independent Get-AuthenticodeSignature gate. The pattern parameter is now required (no wildcard default), and the verify gate derives the files it checks from that same pattern so signing scope == verification scope.
  • OneBranchPipelines/stages/build-windows-single-stage.yml — added signWindowsBinaries param (default true); signs the extension right after "Build PYD" using the exact filename (ddbc_bindings.cp$(shortPyVer)-$(pydArch).pyd, where pydArch maps arch → amd64/arm64/win32); added a post-bdist_wheel step that unpacks the built wheel read-only and asserts the embedded .pyd is Authenticode Valid.
  • OneBranchPipelines/build-release-package-pipeline.yml — added the signWindowsBinaries pipeline parameter and threaded it into the Windows stage. Not gated on oneBranchType, so signing runs in Official + NonOfficial.

ADO validation evidence

Validated on ADO pipeline Build-Release-Package-Pipeline (definitionId 2199), run 165555 (build 26219.3), branch dev/saurabh/sign-pyd-files, queued as NonOfficial with signWindowsBinaries=true. All 9 Windows stages (py3.10–3.14, x64 + arm64) completed succeeded:

  • ESRP MalwareScanning - Native extension: succeeded (9/9)
  • ESRP CodeSigning - Native extension (.pyd): succeeded (9/9)
  • Verify Authenticode signature (native extension): ddbc_bindings.cp313-amd64.pyd: Valid [CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US] → "All signed file(s) are Authenticode 'Valid'."
  • Verify signed .pyd inside built wheel: unpacked the built wheel → ddbc_bindings.cp311-amd64.pyd: Valid ... → "the .pyd inside the built wheel is Authenticode 'Valid'."

AB#46467

…official builds

Signs the compiled ddbc_bindings.*.pyd extension with the CP-230012
Authenticode certificate before it is packaged into the wheel by
setup.py bdist_wheel. Because the .pyd is built in a dedicated step
before packaging, we sign it in place (no wheel unpack/repack), so wheel
RECORD hashes stay correct.

- Rewrite compound-esrp-code-signing-step.yml (previously disabled) into a
  working native-binary signer: EsrpMalwareScanning + EsrpCodeSigning
  (SigntoolSign+Verify) + Authenticode verification gate.
- Wire signing into build-windows-single-stage.yml after Build PYD, add a
  post-bdist_wheel step that verifies the .pyd embedded in the wheel is
  Authenticode Valid (signing evidence).
- Add signWindowsBinaries parameter (default true), threaded through the
  main pipeline; not gated on oneBranchType so signing runs in both
  Official and NonOfficial runs.

AB#46467

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72f9edcc-d3cb-4bec-beed-f90445857f80
Copilot AI lite review requested due to automatic review settings August 7, 2026 15:38
@github-actions github-actions Bot added the pr-size: medium Moderate update size label Aug 7, 2026
Comment thread OneBranchPipelines/steps/compound-esrp-code-signing-step.yml Dismissed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the OneBranch build pipeline to Authenticode-sign the compiled Windows native extension (ddbc_bindings.*.pyd) using ESRP (CP-230012) before wheel packaging, so produced wheels embed a signed .pyd for both Official and NonOfficial runs.

Changes:

  • Reworks the ESRP signing step template to run malware scan → code signing → Authenticode verification for native binaries.
  • Adds a signWindowsBinaries parameter to the Windows build stage and signs the .pyd immediately after it is built.
  • Threads the new signing toggle through the top-level build pipeline and adds a post-build check verifying the .pyd inside the built wheel is Valid.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
OneBranchPipelines/steps/compound-esrp-code-signing-step.yml Implements ESRP malware scanning + Authenticode signing + signature verification for native Windows binaries.
OneBranchPipelines/stages/build-windows-single-stage.yml Adds a signing toggle, calls the signing template after building the .pyd, and verifies the signed .pyd is present/valid inside the built wheel.
OneBranchPipelines/build-release-package-pipeline.yml Introduces and wires a signWindowsBinaries pipeline parameter into the Windows stage template.

Comment thread OneBranchPipelines/steps/compound-esrp-code-signing-step.yml Outdated
Comment thread OneBranchPipelines/stages/build-windows-single-stage.yml Outdated
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

📊 Code Coverage Report

🔥 Diff Coverage

100%


🎯 Overall Coverage

82%


📈 Total Lines Covered: 7368 out of 8963
📁 Project: mssql-python


Diff Coverage

Diff: main...HEAD, staged and unstaged changes

No lines with coverage information in this diff.


📋 Files Needing Attention

📉 Files with overall lowest coverage (click to expand)
mssql_python.pybind.logger_bridge.cpp: 59.2%
mssql_python.pybind.ddbc_bindings.h: 59.9%
mssql_python.pybind.logger_bridge.hpp: 70.8%
mssql_python.pybind.ddbc_bindings.cpp: 76.6%
mssql_python.__init__.py: 77.6%
mssql_python.row.py: 77.6%
mssql_python.ddbc_bindings.py: 79.6%
mssql_python.pybind.connection.connection_pool.cpp: 81.4%
mssql_python.pybind.connection.connection.cpp: 84.3%
mssql_python.logging.py: 85.5%

🔗 Quick Links

⚙️ Build Summary 📋 Coverage Details

View Azure DevOps Build

Browse Full Coverage Report

@saurabh500
Saurabh Singh (saurabh500) marked this pull request as draft August 7, 2026 17:09
Address code-review feedback on the Windows native-extension signing:

- Sign a specifically-named file instead of a broad net. The caller now
  passes the exact extension name (ddbc_bindings.cp<ver>-<arch>.pyd via a
  new pydArch stage variable: x64->amd64, arm64->arm64, x86->win32) rather
  than a ddbc_bindings.cp<ver>-*.pyd wildcard.
- Make the template pattern parameter required (drop the *.pyd default) so
  callers must scope signing explicitly.
- Verification gate now derives its file list from the same pattern that was
  signed instead of rescanning all *.pyd/*.dll, so malware-scan, sign, and
  verify scopes stay identical (previously it could fail on unrelated
  binaries the caller intentionally excluded).
- Fix a misleading comment that claimed only ddbc_bindings.*.pyd is present
  in mssql_python\ during signing; build.bat also copies the vcredist
  msvcp140.dll there, which is already Microsoft-signed and not ours to sign.

AB#46467

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72f9edcc-d3cb-4bec-beed-f90445857f80
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-size: medium Moderate update size

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants