sign github macos releases with developer id
custom release / build-custom-release (push) Successful in 4m53s

This commit is contained in:
2026-08-12 12:22:13 +02:00
parent ca01296949
commit 35b300bd66
3 changed files with 86 additions and 5 deletions
+63 -1
View File
@@ -48,6 +48,53 @@ jobs:
env:
SYNC_REMOTE: origin
- name: Import Developer ID certificate
run: |
set -euo pipefail
keychain_path="$RUNNER_TEMP/syncthing-release-signing.keychain-db"
keychain_password="$(openssl rand -hex 24)"
certificate_path="$RUNNER_TEMP/developer-id-application.p12"
previous_default_keychain="$(security default-keychain -d user 2>/dev/null | sed 's/[ "]//g' || true)"
echo "CUSTOM_RELEASE_KEYCHAIN_PATH=$keychain_path" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_KEYCHAIN_PASSWORD=$keychain_password" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_CERTIFICATE_PATH=$certificate_path" >> "$GITHUB_ENV"
echo "CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN=$previous_default_keychain" >> "$GITHUB_ENV"
if [ -z "$DEVELOPER_ID_APPLICATION_P12_BASE64" ]; then
echo "DEVELOPER_ID_APPLICATION_P12_BASE64 secret is required" >&2
exit 1
fi
if [ -z "$DEVELOPER_ID_APPLICATION_P12_PASSWORD" ]; then
echo "DEVELOPER_ID_APPLICATION_P12_PASSWORD secret is required" >&2
exit 1
fi
printf '%s' "$DEVELOPER_ID_APPLICATION_P12_BASE64" | base64 -D > "$certificate_path"
security create-keychain -p "$keychain_password" "$keychain_path"
security set-keychain-settings -lut 21600 "$keychain_path"
security unlock-keychain -p "$keychain_password" "$keychain_path"
security import "$certificate_path" -k "$keychain_path" -P "$DEVELOPER_ID_APPLICATION_P12_PASSWORD" -A -T /usr/bin/codesign -T /usr/bin/security
security list-keychains -d user -s "$keychain_path"
security default-keychain -d user -s "$keychain_path"
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$keychain_password" "$keychain_path"
identity_output="$(security find-identity -v -p codesigning "$keychain_path")"
printf '%s\n' "$identity_output"
codesign_identity="$(printf '%s\n' "$identity_output" | sed -n 's/.*"\(Developer ID Application:[^"]*\)".*/\1/p' | head -n 1)"
if [ -z "$codesign_identity" ]; then
echo "Developer ID Application signing identity is required in DEVELOPER_ID_APPLICATION_P12_BASE64" >&2
exit 1
fi
probe_binary="$RUNNER_TEMP/codesign-probe"
cp /usr/bin/true "$probe_binary"
codesign --force --dryrun --sign "$codesign_identity" --keychain "$keychain_path" --options runtime --timestamp "$probe_binary"
echo "CUSTOM_RELEASE_CODESIGN_IDENTITY=$codesign_identity" >> "$GITHUB_ENV"
env:
DEVELOPER_ID_APPLICATION_P12_BASE64: ${{ secrets.DEVELOPER_ID_APPLICATION_P12_BASE64 }}
DEVELOPER_ID_APPLICATION_P12_PASSWORD: ${{ secrets.DEVELOPER_ID_APPLICATION_P12_PASSWORD }}
- name: Build patched Syncthing release
run: |
case "$(uname -m)" in
@@ -63,7 +110,9 @@ jobs:
CUSTOM_RELEASE_PUSH: "1"
CUSTOM_RELEASE_PUSH_BRANCH: "0"
CUSTOM_RELEASE_REMOTE: origin
CUSTOM_RELEASE_SIGN_DARWIN: "0"
CUSTOM_RELEASE_CODESIGN_TEAM_ID: "NG5W75WE8U"
CUSTOM_RELEASE_SIGN_DARWIN: "1"
CUSTOM_RELEASE_REQUIRE_GATEKEEPER_ASSESSMENT: "0"
CUSTOM_RELEASE_CREATE_GITEA_RELEASE: "0"
GH_TOKEN: ${{ github.token }}
@@ -85,3 +134,16 @@ jobs:
CUSTOM_RELEASE_UPSTREAM_TAG: ${{ github.event.inputs.upstream_tag }}
CUSTOM_RELEASE_SUFFIX: ${{ github.event.inputs.suffix || 'stignore.7' }}
GH_TOKEN: ${{ github.token }}
- name: Delete temporary keychain
if: always()
run: |
if [ -n "${CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN:-}" ] && [ -e "$CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN" ]; then
security default-keychain -d user -s "$CUSTOM_RELEASE_PREVIOUS_DEFAULT_KEYCHAIN" || true
fi
if [ -n "${CUSTOM_RELEASE_KEYCHAIN_PATH:-}" ]; then
security delete-keychain "$CUSTOM_RELEASE_KEYCHAIN_PATH" || true
fi
if [ -n "${CUSTOM_RELEASE_CERTIFICATE_PATH:-}" ]; then
rm -f "$CUSTOM_RELEASE_CERTIFICATE_PATH"
fi
+2 -3
View File
@@ -41,9 +41,8 @@ matching custom tag already exists, pushes only the `<upstream>-stignore.7` tag
by default, and publishes release assets on the CI host running the workflow.
The local `custom/<version>` branch is only pushed when
`CUSTOM_RELEASE_PUSH_BRANCH=1` is set. The workflow builds macOS arm64, Linux
amd64, and Linux arm64 archives. Gitea signs its macOS build with the configured
Developer ID certificate; GitHub builds an unsigned macOS archive until the
equivalent signing secrets are configured there.
amd64, and Linux arm64 archives. Both hosts sign their macOS builds with their
configured Developer ID certificate.
The patch makes root-level `.stignore` sync like regular folder content while
keeping `.stfolder` and `.stversions` protected as internal Syncthing paths.
@@ -30,13 +30,33 @@ setup() {
run rg -n 'CUSTOM_RELEASE_CREATE_GITEA_RELEASE: "0"' "$GITHUB_WORKFLOW"
[ "$status" -eq 0 ]
run rg -n 'CUSTOM_RELEASE_SIGN_DARWIN: "0"' "$GITHUB_WORKFLOW"
run rg -n 'CUSTOM_RELEASE_SIGN_DARWIN: "1"' "$GITHUB_WORKFLOW"
[ "$status" -eq 0 ]
run rg -n 'tea|ffmini_macos_arm64' "$GITHUB_WORKFLOW"
[ "$status" -ne 0 ]
}
@test "github imports signing secrets into a disposable keychain" {
run rg -n 'DEVELOPER_ID_APPLICATION_P12_BASE64:.*secrets.DEVELOPER_ID_APPLICATION_P12_BASE64' "$GITHUB_WORKFLOW"
[ "$status" -eq 0 ]
run rg -n 'DEVELOPER_ID_APPLICATION_P12_PASSWORD:.*secrets.DEVELOPER_ID_APPLICATION_P12_PASSWORD' "$GITHUB_WORKFLOW"
[ "$status" -eq 0 ]
run rg -n 'security import .* -P "\$DEVELOPER_ID_APPLICATION_P12_PASSWORD"' "$GITHUB_WORKFLOW"
[ "$status" -eq 0 ]
run rg -n 'if: always\(\)' "$GITHUB_WORKFLOW"
[ "$status" -eq 0 ]
run rg -n 'security delete-keychain "\$CUSTOM_RELEASE_KEYCHAIN_PATH"' "$GITHUB_WORKFLOW"
[ "$status" -eq 0 ]
run rg -n 'rm -f "\$CUSTOM_RELEASE_CERTIFICATE_PATH"' "$GITHUB_WORKFLOW"
[ "$status" -eq 0 ]
}
@test "custom release runs as one job on ffmini macos runner" {
run rg -n 'runs-on:[[:space:]]*ffmini_macos_arm64' "$WORKFLOW"
[ "$status" -eq 0 ]