fix(ci/release): archive unsigned + codesign Developer ID directly
ci / web (push) Successful in 26s
ci / docs-site (push) Successful in 29s
apple / swift (push) Successful in 1m18s
ci / rust (push) Successful in 1m24s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
deb / build-publish (push) Successful in 3m2s
docker / deploy-docs (push) Successful in 17s
rpm / build-publish (push) Successful in 4m19s
ci / web (push) Successful in 26s
ci / docs-site (push) Successful in 29s
apple / swift (push) Successful in 1m18s
ci / rust (push) Successful in 1m24s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
deb / build-publish (push) Successful in 3m2s
docker / deploy-docs (push) Successful in 17s
rpm / build-publish (push) Successful in 4m19s
xcodebuild's archive gate demands a provisioning profile for the app's keychain-access-groups entitlement (the 'Keychain Sharing' capability) under both automatic AND manual signing — even though a Developer ID app honours that team-prefixed entitlement at runtime with no profile. So manual signing just traded the -61 keychain error for 'requires a provisioning profile'. Sidestep the gate: archive with CODE_SIGNING_ALLOWED=NO, then codesign the app bundle directly with the Developer ID identity, hardened runtime and a secure timestamp, applying the entitlements via --entitlements (with $(AppIdentifierPrefix) resolved to the team prefix, which codesign won't expand). Safe because the bundle is a single statically-linked binary — static PunktfunkCore.xcframework, SPM static products, macOS 14 target, no Embed-Frameworks phase — so there is no nested code to sign inside-out. No Apple Developer portal profile or new secret needed. iOS App Store path unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -120,50 +120,51 @@ jobs:
|
|||||||
printf '%s' "$ASC_P8" > "$RUNNER_TEMP/asc.p8"
|
printf '%s' "$ASC_P8" > "$RUNNER_TEMP/asc.p8"
|
||||||
chmod 600 "$RUNNER_TEMP/asc.p8"
|
chmod 600 "$RUNNER_TEMP/asc.p8"
|
||||||
|
|
||||||
- name: Archive macOS
|
- name: Archive macOS (unsigned — signed by codesign below)
|
||||||
run: |
|
run: |
|
||||||
# Manual Developer ID signing — same reasoning as the export step below. With
|
# Archive WITHOUT signing, then codesign with Developer ID in the next step. We do
|
||||||
# -allowProvisioningUpdates the archive runs AUTOMATIC signing, which tries to mint
|
# NOT let xcodebuild sign during archive because the app's keychain-access-groups
|
||||||
# an Apple Development cert + a "Mac App Development" profile for io.unom.punktfunk:
|
# entitlement is the "Keychain Sharing" capability, and Xcode's archive gate demands
|
||||||
# installing that cert into the CI keychain fails (DVTSecErrorDomain -61 "Write
|
# a provisioning profile for it under BOTH automatic and manual signing — even
|
||||||
# permissions error") and no such profile exists — a Developer ID DMG needs
|
# though a Developer ID app honours that team-prefixed entitlement at RUNTIME with
|
||||||
# neither. Pin the Developer ID identity and no profile: the app is non-sandboxed
|
# no profile (the gate is an Xcode build-phase check, not a real requirement). Raw
|
||||||
# and its lone entitlement (keychain-access-groups, team-prefixed) is authorized by
|
# codesign has no such gate. Safe because the bundle is a single statically-linked
|
||||||
# the Developer ID team itself, so no provisioning profile is required. The ASC key
|
# binary: static PunktfunkCore.xcframework, SPM static products, macOS 14 target (no
|
||||||
# is still staged above for notarytool + the iOS App Store archive.
|
# embedded Swift dylibs), and no Embed-Frameworks phase — so nothing nested to sign.
|
||||||
DEVELOPER_DIR="$XCODE_DEV_DIR" xcodebuild archive \
|
DEVELOPER_DIR="$XCODE_DEV_DIR" xcodebuild archive \
|
||||||
-project "$PROJECT" -scheme Punktfunk \
|
-project "$PROJECT" -scheme Punktfunk \
|
||||||
-destination 'generic/platform=macOS' \
|
-destination 'generic/platform=macOS' \
|
||||||
-archivePath "$RUNNER_TEMP/Punktfunk-macos.xcarchive" \
|
-archivePath "$RUNNER_TEMP/Punktfunk-macos.xcarchive" \
|
||||||
MARKETING_VERSION="$VERSION" CURRENT_PROJECT_VERSION="$BUILD_NUM" \
|
MARKETING_VERSION="$VERSION" CURRENT_PROJECT_VERSION="$BUILD_NUM" \
|
||||||
CODE_SIGN_STYLE=Manual \
|
CODE_SIGNING_ALLOWED=NO
|
||||||
CODE_SIGN_IDENTITY="Developer ID Application" \
|
|
||||||
DEVELOPMENT_TEAM="$TEAM_ID" \
|
|
||||||
PROVISIONING_PROFILE_SPECIFIER=""
|
|
||||||
|
|
||||||
- name: Export macOS (Developer ID)
|
- name: Sign macOS app (Developer ID, hardened runtime)
|
||||||
run: |
|
run: |
|
||||||
cat > "$RUNNER_TEMP/export-devid.plist" <<EOF
|
APP="$RUNNER_TEMP/Punktfunk-macos.xcarchive/Products/Applications/Punktfunk.app"
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
# codesign does NOT expand $(AppIdentifierPrefix) (an Xcode build-setting var), so
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
# resolve it to the real team prefix — otherwise keychain-access-groups would be the
|
||||||
<plist version="1.0">
|
# literal string instead of the team-scoped group.
|
||||||
<dict>
|
RESOLVED="$RUNNER_TEMP/Punktfunk.entitlements"
|
||||||
<key>method</key><string>developer-id</string>
|
sed "s/\$(AppIdentifierPrefix)/${TEAM_ID}./g" \
|
||||||
<key>teamID</key><string>$TEAM_ID</string>
|
clients/apple/Config/Punktfunk.entitlements > "$RESOLVED"
|
||||||
<key>destination</key><string>export</string>
|
# Inside-out: sign any nested Mach-O first (defensive — the static build normally
|
||||||
<!-- Manual + explicit cert: with -allowProvisioningUpdates Xcode prefers
|
# has none), then the app bundle with the resolved entitlements + hardened runtime +
|
||||||
CLOUD-managed Developer ID signing, which the App-Manager-role API key
|
# secure timestamp, which is what notarization requires.
|
||||||
can't do ("Cloud signing permission error") and it never falls back to
|
if [ -d "$APP/Contents/Frameworks" ]; then
|
||||||
the perfectly valid local identity. -->
|
find "$APP/Contents/Frameworks" -depth \( -name '*.framework' -o -name '*.dylib' \) \
|
||||||
<key>signingStyle</key><string>manual</string>
|
-print0 | while IFS= read -r -d '' f; do
|
||||||
<key>signingCertificate</key><string>Developer ID Application</string>
|
codesign --force --options runtime --timestamp \
|
||||||
</dict>
|
--sign "Developer ID Application" "$f"
|
||||||
</plist>
|
done
|
||||||
EOF
|
fi
|
||||||
DEVELOPER_DIR="$XCODE_DEV_DIR" xcodebuild -exportArchive \
|
codesign --force --options runtime --timestamp \
|
||||||
-archivePath "$RUNNER_TEMP/Punktfunk-macos.xcarchive" \
|
--entitlements "$RESOLVED" \
|
||||||
-exportOptionsPlist "$RUNNER_TEMP/export-devid.plist" \
|
--sign "Developer ID Application" "$APP"
|
||||||
-exportPath "$RUNNER_TEMP/export-devid"
|
codesign --verify --strict --verbose=2 "$APP"
|
||||||
|
# Stage where the DMG step expects it ($RUNNER_TEMP/export-devid/Punktfunk.app).
|
||||||
|
mkdir -p "$RUNNER_TEMP/export-devid"
|
||||||
|
rm -rf "$RUNNER_TEMP/export-devid/Punktfunk.app"
|
||||||
|
cp -R "$APP" "$RUNNER_TEMP/export-devid/Punktfunk.app"
|
||||||
|
|
||||||
- name: Notarized DMG
|
- name: Notarized DMG
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
Reference in New Issue
Block a user