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.
 

Reply via email to