Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 0 additions & 7 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ on:
push:
branches: [main]
workflow_dispatch:
inputs:
publish_authorized_artifact:
description: Sign and notarize macOS packages with the configured Apple credentials
required: false
type: boolean
default: false

permissions:
contents: read
Expand Down Expand Up @@ -69,7 +63,6 @@ jobs:
- name: Install pinned Tauri CLI
run: cargo install tauri-cli --version 2.8.4 --locked
- name: Configure Developer ID signing and notarization
if: ${{ inputs.publish_authorized_artifact == true }}
env:
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ for every platform supported by Chat2DB Community:
Every desktop package embeds the matching `chat2db` headless CLI beside the
shared Java, Community-classpath, and driver-pack resources.

macOS builds are ad-hoc signed for test packages by default. A manual run with
`publish_authorized_artifact=true` enables the configured Developer ID signing
and notarization path.
macOS packages are always signed with the configured Developer ID Application
identity and notarized by Apple before upload. Packaging fails closed when the
signing or notarization configuration is unavailable.

## Current state

Expand Down
2 changes: 1 addition & 1 deletion packaging/macos/THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Third-Party Notices

This local test package contains the exact original Chat2DB Community frontend
This desktop package contains the exact original Chat2DB Community frontend
and fixed Java compatibility classpath pinned by this repository. Their source
revision, artifact names, byte lengths, and SHA-256 digests are recorded in:

Expand Down
2 changes: 1 addition & 1 deletion scripts/build-linux-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ cp -- "${appimage_artifacts[0]}" "${deb_artifacts[0]}" "${rpm_artifacts[0]}" "${
cd "${package_directory}"
sha256sum ./*.AppImage ./*.deb ./*.rpm > SHA256SUMS
{
echo "Chat2DB Rust Linux test package"
echo "Chat2DB Rust Linux package"
echo "architecture=$(uname -m)"
echo "target=linux"
echo "rust_toolchain=${rust_toolchain}"
Expand Down
152 changes: 78 additions & 74 deletions scripts/build-macos-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,38 @@ if [[ "${rust_version}" != rustc\ 1.88.0\ * ]]; then
exit 1
fi

signing_identity="${APPLE_SIGNING_IDENTITY:-}"
signing_keychain="${CHAT2DB_SIGNING_KEYCHAIN:-}"
notary_profile="${CHAT2DB_NOTARY_KEYCHAIN_PROFILE:-}"
expected_team_id="${APPLE_TEAM_ID:-}"
if [[ -z "${signing_identity}" || "${signing_identity}" == "-" ]]; then
echo "macOS packaging requires a Developer ID signing identity" >&2
exit 1
fi
if [[ -z "${signing_keychain}" || "${signing_keychain}" != /* || ! -f "${signing_keychain}" || -L "${signing_keychain}" ]]; then
echo "macOS packaging requires a safe signing keychain" >&2
exit 1
fi
if [[ -z "${notary_profile}" ]]; then
echo "macOS packaging requires a notarytool keychain profile" >&2
exit 1
fi
if [[ -z "${expected_team_id}" ]]; then
echo "macOS packaging requires APPLE_TEAM_ID" >&2
exit 1
fi

sign_developer_id_code() {
local code_path="$1"
codesign --force \
--options runtime \
--sign "${signing_identity}" \
--keychain "${signing_keychain}" \
--timestamp \
"${code_path}"
codesign --verify --strict --verbose=2 "${code_path}"
}

cli_build_target="${repository_root}/target/macos-cli-build"
cli_resource_directory="${repository_root}/target/macos-cli"
rm -rf -- "${cli_build_target}"
Expand All @@ -105,6 +137,21 @@ CARGO_TARGET_DIR="${cli_build_target}" RUSTUP_TOOLCHAIN="${rust_toolchain}" \
cargo build -p chat2db-cli --release --locked
cp -- "${cli_build_target}/release/chat2db" "${cli_resource_directory}/chat2db"
chmod 755 "${cli_resource_directory}/chat2db"
sign_developer_id_code "${cli_resource_directory}/chat2db"

signed_runtime_macho_count=0
while IFS= read -r -d '' runtime_file; do
if [[ "$(file -b "${runtime_file}")" != *"Mach-O"* ]]; then
continue
fi
sign_developer_id_code "${runtime_file}"
signed_runtime_macho_count=$((signed_runtime_macho_count + 1))
done < <(find "${repository_root}/target/macos-runtime" -type f -print0)
if [[ "${signed_runtime_macho_count}" -eq 0 ]]; then
echo "macOS Java runtime contains no Mach-O code to sign" >&2
exit 1
fi
echo "Signed ${signed_runtime_macho_count} macOS Java runtime binaries"

staged_resource_root="${build_target}/release/chat2db"
if [[ -L "${staged_resource_root}" || ( -e "${staged_resource_root}" && ! -d "${staged_resource_root}" ) ]]; then
Expand Down Expand Up @@ -133,41 +180,15 @@ if [[ ! -d "${app_path}" || -L "${app_path}" ]]; then
exit 1
fi

signing_identity="${APPLE_SIGNING_IDENTITY:--}"
signing_keychain="${CHAT2DB_SIGNING_KEYCHAIN:-}"
notary_profile="${CHAT2DB_NOTARY_KEYCHAIN_PROFILE:-}"
expected_team_id="${APPLE_TEAM_ID:-}"
notarization_enabled=false
notarization_status="not-submitted"
distribution_status="internal-test-only"

if [[ -n "${notary_profile}" ]]; then
if [[ "${signing_identity}" == "-" ]]; then
echo "notarization requires a Developer ID signing identity" >&2
exit 1
fi
if [[ -z "${signing_keychain}" || "${signing_keychain}" != /* || ! -f "${signing_keychain}" || -L "${signing_keychain}" ]]; then
echo "notarization requires a safe signing keychain" >&2
exit 1
fi
if [[ -z "${expected_team_id}" ]]; then
echo "notarization requires APPLE_TEAM_ID" >&2
exit 1
fi
notarization_enabled=true
fi
distribution_status="developer-id-signed"

if [[ "${signing_identity}" == "-" ]]; then
codesign --force --deep --sign - --timestamp=none "${app_path}"
# Tauri signs the application bundle after copying the pre-signed CLI and Java
# runtime resources. Do not deep re-sign the app, which would replace nested
# hardened-runtime signatures and their trusted timestamps.
CHAT2DB_REQUIRE_DEVELOPER_ID_SIGNATURE=true \
APPLE_TEAM_ID="${expected_team_id}" \
"${repository_root}/scripts/verify-macos-package.sh" "${app_path}"
else
# Tauri owns the only Developer ID signing pass so nested runtime
# entitlements and signatures are not destroyed by a deep re-sign.
CHAT2DB_REQUIRE_DEVELOPER_ID_SIGNATURE=true \
APPLE_TEAM_ID="${expected_team_id}" \
"${repository_root}/scripts/verify-macos-package.sh" "${app_path}"
distribution_status="developer-id-signed"
fi

notarize_artifact() {
local artifact_path="$1"
Expand Down Expand Up @@ -218,35 +239,27 @@ verify_developer_id_signature() {

verify_packaged_app() {
local packaged_app="$1"
if [[ "${signing_identity}" == "-" ]]; then
CHAT2DB_REQUIRE_DEVELOPER_ID_SIGNATURE=true \
APPLE_TEAM_ID="${expected_team_id}" \
"${repository_root}/scripts/verify-macos-package.sh" "${packaged_app}"
else
CHAT2DB_REQUIRE_DEVELOPER_ID_SIGNATURE=true \
APPLE_TEAM_ID="${expected_team_id}" \
"${repository_root}/scripts/verify-macos-package.sh" "${packaged_app}"
fi
if [[ "${notarization_enabled}" == true ]]; then
xcrun stapler validate "${packaged_app}"
spctl --assess --type execute --verbose=4 "${packaged_app}"
fi
xcrun stapler validate "${packaged_app}"
spctl --assess --type execute --verbose=4 "${packaged_app}"
}

if [[ "${notarization_enabled}" == true ]]; then
notary_directory="$(mktemp -d "${target_root}/.chat2db-notary.XXXXXX")"
notary_app_zip="${notary_directory}/Chat2DB-Rust.app.zip"
ditto -c -k --sequesterRsrc --keepParent "${app_path}" "${notary_app_zip}"
notarize_artifact "${notary_app_zip}"
xcrun stapler staple "${app_path}"
xcrun stapler validate "${app_path}"
spctl --assess --type execute --verbose=4 "${app_path}"
rm -rf -- "${notary_directory}"
notary_directory=""
CHAT2DB_REQUIRE_DEVELOPER_ID_SIGNATURE=true \
APPLE_TEAM_ID="${expected_team_id}" \
"${repository_root}/scripts/verify-macos-package.sh" "${app_path}"
notarization_status="accepted"
distribution_status="developer-id-notarized"
fi
notary_directory="$(mktemp -d "${target_root}/.chat2db-notary.XXXXXX")"
notary_app_zip="${notary_directory}/Chat2DB-Rust.app.zip"
ditto -c -k --sequesterRsrc --keepParent "${app_path}" "${notary_app_zip}"
notarize_artifact "${notary_app_zip}"
xcrun stapler staple "${app_path}"
xcrun stapler validate "${app_path}"
spctl --assess --type execute --verbose=4 "${app_path}"
rm -rf -- "${notary_directory}"
notary_directory=""
CHAT2DB_REQUIRE_DEVELOPER_ID_SIGNATURE=true \
APPLE_TEAM_ID="${expected_team_id}" \
"${repository_root}/scripts/verify-macos-package.sh" "${app_path}"
notarization_status="accepted"
distribution_status="developer-id-notarized"

version="$(awk '
/^\[workspace.package\]$/ { in_package = 1; next }
Expand Down Expand Up @@ -296,21 +309,12 @@ hdiutil create \
rm -rf -- "${staging_directory}"
staging_directory=""

if [[ "${signing_identity}" != "-" ]]; then
if [[ -n "${signing_keychain}" ]]; then
codesign --force --sign "${signing_identity}" --keychain "${signing_keychain}" --timestamp "${dmg_path}"
else
codesign --force --sign "${signing_identity}" --timestamp "${dmg_path}"
fi
verify_developer_id_signature "${dmg_path}" "macOS DMG"
fi

if [[ "${notarization_enabled}" == true ]]; then
notarize_artifact "${dmg_path}"
xcrun stapler staple "${dmg_path}"
xcrun stapler validate "${dmg_path}"
spctl --assess --type open --context context:primary-signature --verbose=4 "${dmg_path}"
fi
codesign --force --sign "${signing_identity}" --keychain "${signing_keychain}" --timestamp "${dmg_path}"
verify_developer_id_signature "${dmg_path}" "macOS DMG"
notarize_artifact "${dmg_path}"
xcrun stapler staple "${dmg_path}"
xcrun stapler validate "${dmg_path}"
spctl --assess --type open --context context:primary-signature --verbose=4 "${dmg_path}"
hdiutil verify "${dmg_path}"

verification_directory="$(mktemp -d "${target_root}/.chat2db-dmg-verify.XXXXXX")"
Expand All @@ -335,7 +339,7 @@ signing_authority="$(awk -F= '/^Authority=/ { print $2; exit }' <<<"${signature_
signing_team_id="${signing_team_id:-none}"
signing_authority="${signing_authority:-adhoc}"
cat > "${package_directory}/BUILD-MANIFEST.txt" <<EOF
Chat2DB Rust macOS test package
Chat2DB Rust macOS package
version=${version}
architecture=${artifact_arch}
git_commit=${git_commit}
Expand Down
2 changes: 1 addition & 1 deletion scripts/build-windows-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ cp -- "${msi_artifacts[0]}" "${package_directory}/"
cd "${package_directory}"
sha256sum ./*.exe ./*.msi > SHA256SUMS
{
echo "Chat2DB Rust Windows test package"
echo "Chat2DB Rust Windows package"
echo "architecture=x86_64"
echo "target=windows"
echo "rust_toolchain=${rust_toolchain}"
Expand Down
Loading