This is an automated email from the ASF dual-hosted git repository.
amoeba pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new e8b7b4e35e GH-49686: [C++][FlightRPC][ODBC][Release] Create signing
script for Windows FlightSQL ODBC build (#49788)
e8b7b4e35e is described below
commit e8b7b4e35e231a0fcdbfa74f6a6b0075108dd5dc
Author: Bryce Mecum <[email protected]>
AuthorDate: Tue Apr 21 22:25:22 2026 -0700
GH-49686: [C++][FlightRPC][ODBC][Release] Create signing script for Windows
FlightSQL ODBC build (#49788)
### Rationale for this change
We need a script for the release manager to run during the release to
locally sign the Windows artifacts for the FlightSQL ODBC driver.
Ref: https://github.com/apache/arrow/issues/49404
### What changes are included in this PR?
- New script, `07-flightsql-odbc-upload.sh`
- Update to release guide
- Renamed other release scripts to make space in the numbering scheme:
- 07-publish-gh-release -> 08
- 08-binary-verify -> 09
- 08-vote-emai -> 10
### Are these changes tested?
Not 100% but I've tested each step separately. I tested on my fork using
fake tags and releases.
### Are there any user-facing changes?
No.
* GitHub Issue: #49686
Lead-authored-by: Bryce Mecum <[email protected]>
Co-authored-by: Sutou Kouhei <[email protected]>
Signed-off-by: Bryce Mecum <[email protected]>
---
.pre-commit-config.yaml | 4 +-
dev/release/.env.example | 7 +
dev/release/07-flightsqlodbc-upload.sh | 182 +++++++++++++++++++++
...lish-gh-release.sh => 08-publish-gh-release.sh} | 0
.../{08-binary-verify.sh => 09-binary-verify.sh} | 0
...09-vote-email-test.rb => 10-vote-email-test.rb} | 2 +-
dev/release/{09-vote-email.sh => 10-vote-email.sh} | 0
docs/source/developers/release.rst | 17 +-
8 files changed, 207 insertions(+), 5 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 0544ff11bf..2b7e3ce763 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -349,7 +349,8 @@ repos:
?^cpp/examples/tutorial_examples/run\.sh$|
?^cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc\.sh$|
?^dev/release/05-binary-upload\.sh$|
- ?^dev/release/08-binary-verify\.sh$|
+ ?^dev/release/07-flightsqlodbc-upload\.sh$|
+ ?^dev/release/09-binary-verify\.sh$|
?^dev/release/binary-recover\.sh$|
?^dev/release/post-03-binary\.sh$|
?^dev/release/post-08-docs\.sh$|
@@ -376,6 +377,7 @@ repos:
?^ci/scripts/python_test_type_annotations\.sh$|
?^cpp/src/arrow/flight/sql/odbc/install/mac/install_odbc\.sh$|
?^dev/release/05-binary-upload\.sh$|
+ ?^dev/release/07-flightsqlodbc-upload\.sh$|
?^dev/release/binary-recover\.sh$|
?^dev/release/post-03-binary\.sh$|
?^dev/release/post-08-docs\.sh$|
diff --git a/dev/release/.env.example b/dev/release/.env.example
index 67bc944956..3d52269629 100644
--- a/dev/release/.env.example
+++ b/dev/release/.env.example
@@ -34,3 +34,10 @@
#
# You must set this.
#GH_TOKEN=secret
+
+# For 07-flightsqlodbc-upload.sh. See that script for more details.
+#
+# ssl.com credentials in "username|password" format
+#ESIGNER_STOREPASS=username|password
+# ssl.com eSigner secret code (not the PIN)
+#ESIGNER_KEYPASS=otp_secret_code
diff --git a/dev/release/07-flightsqlodbc-upload.sh
b/dev/release/07-flightsqlodbc-upload.sh
new file mode 100755
index 0000000000..c47b5076f9
--- /dev/null
+++ b/dev/release/07-flightsqlodbc-upload.sh
@@ -0,0 +1,182 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# FlightSQL ODBC Release Signing Script
+#
+# This script handles the signing of FlightSQL ODBC Windows binaries and MSI
+# installer. It requires jsign to be configured with ASF code signing
+# credentials. Keep reading below:
+#
+# Required environment variables:
+#
+# ESIGNER_STOREPASS - The ssl.com credentials in "username|password" format
+# ESIGNER_KEYPASS - The ssl.com eSigner secret code (not the PIN)
+#
+# Set these in .env.
+#
+# How to get ESIGNER_KEYPASS:
+#
+# 1. Log into ssl.com
+# 2. In your Dashboard, under "invitations", click the link under the order. Or
+# go to Orders, find the order, expand the order, and click "certificate
+# details"
+# 3. Enter your PIN to get your OTP. This is ESIGNER_KEYPASS.
+#
+# If you don't have access, see https://infra.apache.org/code-signing-use.html.
+
+set -e
+set -u
+set -o pipefail
+
+SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+if [ "$#" -ne 2 ]; then
+ echo "Usage: $0 <version> <rc-num>"
+ exit 1
+fi
+
+. "${SOURCE_DIR}/utils-env.sh"
+
+if [ -z "${ESIGNER_STOREPASS:-}" ]; then
+ echo "ERROR: ESIGNER_STOREPASS is not set" >&2
+ exit 1
+fi
+if [ -z "${ESIGNER_KEYPASS:-}" ]; then
+ echo "ERROR: ESIGNER_KEYPASS is not set" >&2
+ exit 1
+fi
+
+version=$1
+rc=$2
+
+version_with_rc="${version}-rc${rc}"
+tag="apache-arrow-${version_with_rc}"
+
+dll_unsigned="arrow_flight_sql_odbc_unsigned.dll"
+dll_signed="arrow_flight_sql_odbc.dll"
+
+: "${GITHUB_REPOSITORY:=apache/arrow}"
+
+: "${PHASE_DEFAULT:=1}"
+: "${PHASE_SIGN_DLL:=${PHASE_DEFAULT}}"
+: "${PHASE_BUILD_MSI:=${PHASE_DEFAULT}}"
+: "${PHASE_SIGN_MSI:=${PHASE_DEFAULT}}"
+
+if [ "${PHASE_SIGN_DLL}" -eq 0 ] && [ "${PHASE_BUILD_MSI}" -eq 0 ] && [
"${PHASE_SIGN_MSI}" -eq 0 ]; then
+ echo "No phases specified. Exiting."
+ exit 1
+fi
+
+# Utility function to use jsign to check if a file is signed or not
+is_signed() {
+ local file="$1"
+ local exit_code=0
+ jsign extract --format PEM "${file}" >/dev/null 2>&1 || exit_code=$?
+ # jsign writes a PEM file even though it also prints to stdout. Clean up
after
+ # it. Use -f since so it still runs on unsigned files without error.
+ rm -f "${file}.sig.pem"
+ return ${exit_code}
+}
+
+# Use dev/release/tmp for temporary files
+tmp_dir="${SOURCE_DIR}/tmp"
+if [ -e "${tmp_dir}" ]; then
+ echo "ERROR: temp dir already exists: ${tmp_dir}. Remove it manually and run
again." >&2
+ exit 1
+fi
+
+if [ "${PHASE_SIGN_DLL}" -gt 0 ]; then
+ echo "[1/8 Downloading ${dll_unsigned} from release..."
+ gh release download "${tag}" \
+ --repo "${GITHUB_REPOSITORY}" \
+ --pattern "${dll_unsigned}" \
+ --dir "${tmp_dir}"
+ if is_signed "${tmp_dir}/${dll_unsigned}"; then
+ echo "ERROR: ${dll_unsigned} is already signed" >&2
+ exit 1
+ fi
+
+ echo "[2/8 Signing ${dll_unsigned}..."
+ echo "NOTE: Running jsign. You may be prompted for your OTP PIN..."
+ jsign --storetype ESIGNER \
+ --alias d97c5110-c66a-4c0c-ac0c-1cd6af812ee6 \
+ --storepass "${ESIGNER_STOREPASS}" \
+ --keypass "${ESIGNER_KEYPASS}" \
+ --tsaurl="http://ts.ssl.com" \
+ --tsmode RFC3161 \
+ --alg SHA256 \
+ "${tmp_dir}/${dll_unsigned}"
+ mv "${tmp_dir}/${dll_unsigned}" "${tmp_dir}/${dll_signed}"
+ if ! is_signed "${tmp_dir}/${dll_signed}"; then
+ echo "ERROR: ${dll_signed} is not signed" >&2
+ exit 1
+ fi
+
+ echo "[3/8 Uploading signed DLL to GitHub Release..."
+ gh release upload "${tag}" \
+ --repo "${GITHUB_REPOSITORY}" \
+ --clobber \
+ "${tmp_dir}/${dll_signed}"
+fi
+
+if [ "${PHASE_BUILD_MSI}" -gt 0 ]; then
+ echo "[4/8 Triggering odbc_release_step in cpp_extra.yml workflow..."
+ gh workflow run cpp_extra.yml \
+ --repo "${GITHUB_REPOSITORY}" \
+ --ref "${tag}" \
+ --field odbc_release_step=true
+
+ echo "[5/8 Waiting for workflow to complete. This can take a very long
time..."
+ REPOSITORY="${GITHUB_REPOSITORY}" \
+ "${SOURCE_DIR}/utils-watch-gh-workflow.sh" "${tag}" cpp_extra.yml
+fi
+
+if [ "${PHASE_SIGN_MSI}" -gt 0 ]; then
+ echo "[6/8 Downloading unsigned MSI..."
+ gh release download "${tag}" \
+ --repo "${GITHUB_REPOSITORY}" \
+ --pattern "Apache-Arrow-Flight-SQL-ODBC-${version}-win64.msi" \
+ --dir "${tmp_dir}"
+ msi="${tmp_dir}/Apache-Arrow-Flight-SQL-ODBC-${version}-win64.msi"
+ if is_signed "${msi}"; then
+ echo "ERROR: MSI is already signed" >&2
+ exit 1
+ fi
+
+ echo "[7/8 Signing MSI..."
+ echo "NOTE: Running jsign. You may be prompted for your OTP PIN..."
+ jsign --storetype ESIGNER \
+ --alias d97c5110-c66a-4c0c-ac0c-1cd6af812ee6 \
+ --storepass "${ESIGNER_STOREPASS}" \
+ --keypass "${ESIGNER_KEYPASS}" \
+ --tsaurl="http://ts.ssl.com" \
+ --tsmode RFC3161 \
+ --alg SHA256 \
+ "${msi}"
+ if ! is_signed "${msi}"; then
+ echo "ERROR: MSI is not signed" >&2
+ exit 1
+ fi
+
+ echo "[8/8 Uploading signed MSI to GitHub Release..."
+ gh release upload "${tag}" \
+ --repo "${GITHUB_REPOSITORY}" \
+ --clobber \
+ "${msi}"
+fi
diff --git a/dev/release/07-publish-gh-release.sh
b/dev/release/08-publish-gh-release.sh
similarity index 100%
rename from dev/release/07-publish-gh-release.sh
rename to dev/release/08-publish-gh-release.sh
diff --git a/dev/release/08-binary-verify.sh b/dev/release/09-binary-verify.sh
similarity index 100%
rename from dev/release/08-binary-verify.sh
rename to dev/release/09-binary-verify.sh
diff --git a/dev/release/09-vote-email-test.rb
b/dev/release/10-vote-email-test.rb
similarity index 98%
rename from dev/release/09-vote-email-test.rb
rename to dev/release/10-vote-email-test.rb
index bae314b245..2423856c0b 100644
--- a/dev/release/09-vote-email-test.rb
+++ b/dev/release/10-vote-email-test.rb
@@ -24,7 +24,7 @@ class VoteEmailTest < Test::Unit::TestCase
detect_versions
@tag_name_no_rc = "apache-arrow-#{@release_version}"
@archive_name = "apache-arrow-#{@release_version}.tar.gz"
- @script = File.expand_path("dev/release/09-vote-email.sh")
+ @script = File.expand_path("dev/release/10-vote-email.sh")
@tarball_script =
File.expand_path("dev/release/utils-create-release-tarball.sh")
@env = File.expand_path("dev/release/.env")
diff --git a/dev/release/09-vote-email.sh b/dev/release/10-vote-email.sh
similarity index 100%
rename from dev/release/09-vote-email.sh
rename to dev/release/10-vote-email.sh
diff --git a/docs/source/developers/release.rst
b/docs/source/developers/release.rst
index 631019f446..fe5a969737 100644
--- a/docs/source/developers/release.rst
+++ b/docs/source/developers/release.rst
@@ -264,13 +264,24 @@ Build source and binaries and submit them
# NOTE: You need to have GitHub CLI installed to run this script.
dev/release/06-matlab-upload.sh <version> <rc-number>
+ # Sign, build the installer for, and sign the installer for the FlightSQL
+ # ODBC Windows driver
+ #
+ # NOTE: This must be run by a PMC member
+ # Note: You need to have jsign installed and an available credential from
+ # ASF to sign artifacts. Not all PMC members will have access to code
+ # signing.
+ # Note: The script requires setup of ssl.com environment variables.
+ # Note: Invoking this script costs money.
+ dev/release/07-flightsqlodbc-upload.sh <version> <rc-number>
+
# Move the Release Candidate GitHub Release from draft to published state
# This will update the artifacts download URL which will be available for
the
# verification step.
- dev/release/07-publish-gh-release.sh <version> <rc-number>
+ dev/release/08-publish-gh-release.sh <version> <rc-number>
# Start verifications for binaries and wheels
- dev/release/08-binary-verify.sh <version> <rc-number>
+ dev/release/09-binary-verify.sh <version> <rc-number>
Verify the Release
@@ -280,7 +291,7 @@ Verify the Release
# Once the automatic verification has passed start the vote thread
# on [email protected]. To regenerate the email template use
- dev/release/09-vote-email.sh <version> <rc-number>
+ dev/release/10-vote-email.sh <version> <rc-number>
See :ref:`release_verification` for details.