Skip to content

Commit 9d34547

Browse files
beriberikixclaude
andcommitted
Stop publishing a System Extension nobody can install
The release built, signed, notarized, stapled and published USBIPDSystemExtension.systemextension.tar.gz on every tag. No installed component could locate it, and it was not a System Extension bundle by structure: the workflow's `find` for a SwiftPM-produced bundle never matched, so the fallback synthesised one from an inline heredoc with no NSExtension dict and no IOKitPersonalities. It also wrote Contents/embedded.provisionprofile empty whenever DRIVERKIT_PROVISIONING_PROFILE was unset, which was always — so the managed DriverKit entitlements it was signed with were inert. Removed: the product build, the hand-rolled bundle, the profile embed, the signing, the notarization and stapling, the tarball, the checksum extraction, and the systemextension_url / systemextension_sha256 fields in the Homebrew metadata. Verified before removing that nothing consumes them: validate-homebrew-metadata.sh requires only version, archive_url, sha256 and timestamp, and the tap's formula-sync.yml reads only the two per-arch binaries. Signing collapses to one path. usbipd carried com.apple.developer.system-extension.install, a restricted entitlement AMFI kills without an authorising profile — measured as exit 137 on launch — so the workflow had to withhold entitlements whenever no profile was present. With nothing to install, there is nothing restricted to claim: usbipd.entitlements is deleted and every artifact is signed the same way. If a DriverKit extension arrives it will live in an app bundle in /Applications, and that app, not this binary, will need the entitlement. The release notes no longer tell people to run `sudo usbipd install-system-extension`, a command removed some releases ago, and point at the per-arch binaries rather than the compatibility copy. Also drops the CI step that built the deleted product. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017rmyikdjWveP99ZUCDLY89
1 parent 5ecfb55 commit 9d34547

3 files changed

Lines changed: 18 additions & 216 deletions

File tree

.github/workflows/ci.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,6 @@ jobs:
8080
echo "Building main targets..."
8181
swift build --verbose
8282
83-
echo "Building System Extension target..."
84-
swift build --product USBIPDSystemExtension --verbose
85-
8683
echo "Building test server..."
8784
swift build --product QEMUTestServer --verbose
8885

.github/workflows/release.yml

Lines changed: 18 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ env:
3030
# Base64-encoded .provisionprofile carrying the DriverKit managed capabilities.
3131
# Without it the DriverKit entitlements are signed in but inert — see
3232
# Documentation/development/entitlement-validation.md
33-
DRIVERKIT_PROVISIONING_PROFILE: ${{ secrets.DRIVERKIT_PROVISIONING_PROFILE }}
3433

3534
jobs:
3635
release-validation:
@@ -184,11 +183,8 @@ jobs:
184183
185184
echo "🔍 Universal binary: $(lipo -archs "$UNIVERSAL")"
186185
187-
# The rest of the build stays host-architecture: only the CLI is distributed
188-
# to end users, and the system extension is inert (see the formula).
186+
# The rest of the build stays host-architecture: only the CLI is distributed.
189187
swift build --configuration release
190-
echo "🏗️ Building system extension bundle..."
191-
swift build --configuration release --product USBIPDSystemExtension
192188
193189
# Split into per-architecture artifacts. lipo -thin drops the code signature,
194190
# so each slice is signed separately further down — signing before this point
@@ -212,68 +208,6 @@ jobs:
212208
USBIPD_PATH="$ARTIFACTS_DIR/usbipd-$VERSION-macos"
213209
cp "$USBIPD_ARM64" "$USBIPD_PATH"
214210
215-
# Package system extension bundle
216-
echo "📦 Packaging system extension bundle..."
217-
BUNDLE_PATH=$(find .build/release -name "*.systemextension" -type d | head -1)
218-
if [ -n "$BUNDLE_PATH" ]; then
219-
echo "Found system extension bundle at: $BUNDLE_PATH"
220-
cp -R "$BUNDLE_PATH" "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension"
221-
else
222-
echo "Creating system extension bundle structure..."
223-
mkdir -p "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension/Contents/MacOS"
224-
cp .build/release/USBIPDSystemExtension "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension/Contents/MacOS/"
225-
226-
# Create Info.plist for system extension
227-
cat > "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension/Contents/Info.plist" << EOF
228-
<?xml version="1.0" encoding="UTF-8"?>
229-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
230-
<plist version="1.0">
231-
<dict>
232-
<key>CFBundleExecutable</key>
233-
<string>USBIPDSystemExtension</string>
234-
<key>CFBundleIdentifier</key>
235-
<string>com.github.usbipd-mac.systemextension</string>
236-
<key>CFBundleInfoDictionaryVersion</key>
237-
<string>6.0</string>
238-
<key>CFBundleName</key>
239-
<string>USBIPD System Extension</string>
240-
<key>CFBundlePackageType</key>
241-
<string>SYSX</string>
242-
<key>CFBundleShortVersionString</key>
243-
<string>$VERSION</string>
244-
<key>CFBundleVersion</key>
245-
<string>$VERSION</string>
246-
<key>NSSystemExtensionUsageDescription</key>
247-
<string>Enables USB device sharing over IP networks</string>
248-
</dict>
249-
</plist>
250-
EOF
251-
fi
252-
253-
# Copy entitlements files for code signing
254-
echo "📋 Copying entitlements..."
255-
cp Sources/SystemExtension/SystemExtension.entitlements "$ARTIFACTS_DIR/"
256-
cp usbipd.entitlements "$ARTIFACTS_DIR/"
257-
258-
# Embed the provisioning profile into the system extension bundle.
259-
#
260-
# The DriverKit entitlements in SystemExtension.entitlements are managed
261-
# capabilities: codesign will happily embed the keys, but the kernel only
262-
# honours them when the same keys appear in an Apple-issued provisioning
263-
# profile shipped inside the bundle. Without this the entitlements are inert,
264-
# which is indistinguishable at signing time from them working.
265-
if [ -n "$DRIVERKIT_PROVISIONING_PROFILE" ]; then
266-
echo "📋 Embedding provisioning profile..."
267-
if [ -d "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" ]; then
268-
echo "$DRIVERKIT_PROVISIONING_PROFILE" | base64 --decode \
269-
> "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension/Contents/embedded.provisionprofile"
270-
echo "✅ Provisioning profile embedded"
271-
else
272-
echo "::warning::DRIVERKIT_PROVISIONING_PROFILE set but no system extension bundle to embed it in"
273-
fi
274-
else
275-
echo "::warning::No DRIVERKIT_PROVISIONING_PROFILE secret configured. The DriverKit entitlements will be signed into the bundle but will not take effect, so device claiming will fail at runtime. See Documentation/development/entitlement-validation.md"
276-
fi
277211
278212
# Package QEMU test server if available
279213
if [ -f .build/release/QEMUTestServer ]; then
@@ -284,97 +218,34 @@ jobs:
284218
# Code sign binaries if certificates available
285219
if [ -n "$DEVELOPER_ID_CERTIFICATE" ]; then
286220
echo "🔒 Code signing release artifacts..."
287-
# usbipd carries com.apple.developer.system-extension.install, which is a
288-
# RESTRICTED entitlement: AMFI kills a binary that claims it without a
289-
# provisioning profile authorising it. Measured, not assumed — a binary
290-
# signed with just that key and no profile exits 137 on launch.
221+
# usbipd needs no entitlements. It used to carry
222+
# com.apple.developer.system-extension.install so it could activate the
223+
# extension — a RESTRICTED entitlement that AMFI kills without an
224+
# authorising provisioning profile, measured as exit 137 on launch. The
225+
# signing step therefore had to withhold it whenever no profile was
226+
# present, which was always. With the extension gone there is nothing to
227+
# install and nothing restricted to claim, so there is one path.
228+
#
229+
# If a DriverKit extension arrives it will live in an app bundle in
230+
# /Applications, and that app — not this binary — is what will need the
231+
# install entitlement and a profile.
291232
#
292-
# So the entitlements are only applied when a profile is present. Without
293-
# one, sign exactly as before: hardened runtime for notarization, no
294-
# entitlements, and a daemon that actually starts.
295233
# Every usbipd artifact is signed, including both architecture slices:
296234
# lipo -thin strips the signature, so an unsigned slice would ship.
297235
for target in "$USBIPD_PATH" "$USBIPD_ARM64" "$USBIPD_X86_64"; do
298236
[ -f "$target" ] || continue
299-
if [ -n "$DRIVERKIT_PROVISIONING_PROFILE" ]; then
300-
echo " signing $(basename "$target") with entitlements (provisioning profile present)"
301-
codesign --sign "Developer ID Application" --entitlements "$ARTIFACTS_DIR/usbipd.entitlements" --options runtime --timestamp "$target" || echo "::warning::Code signing failed for $(basename "$target")"
302-
else
303-
echo " signing $(basename "$target") without entitlements (no provisioning profile)"
304-
codesign --sign "Developer ID Application" --options runtime --timestamp "$target" || echo "::warning::Code signing failed for $(basename "$target")"
305-
fi
237+
echo " signing $(basename "$target")"
238+
codesign --sign "Developer ID Application" --options runtime --timestamp "$target" || echo "::warning::Code signing failed for $(basename "$target")"
306239
done
307-
if [ -z "$DRIVERKIT_PROVISIONING_PROFILE" ]; then
308-
echo "::warning::usbipd signed without entitlements. It cannot install the System Extension, but it will launch. Set DRIVERKIT_PROVISIONING_PROFILE to enable them."
309-
fi
310240
311-
# Sign system extension bundle
312-
if [ -d "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" ]; then
313-
echo "🔒 Code signing system extension bundle..."
314-
codesign --sign "Developer ID Application" --entitlements "$ARTIFACTS_DIR/SystemExtension.entitlements" --options runtime --timestamp "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" || echo "::warning::Code signing failed for system extension"
315-
fi
316-
317241
if [ -f "$QEMU_SERVER_PATH" ]; then
318242
codesign --sign "Developer ID Application" --timestamp "$QEMU_SERVER_PATH" || echo "::warning::Code signing failed for QEMUTestServer"
319243
fi
320244
echo "✅ Code signing completed"
321-
322-
# Read the entitlements back out of the signatures rather than trusting
323-
# what we passed in. A managed capability that was silently dropped looks
324-
# identical to a successful signing run without this check.
325-
echo "🔍 Verifying embedded entitlements..."
326-
codesign -d --entitlements - --xml "$USBIPD_PATH" 2>/dev/null || echo "::warning::Could not read back usbipd entitlements"
327-
if [ -d "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" ]; then
328-
SYSEXT_ENTITLEMENTS=$(codesign -d --entitlements - --xml "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" 2>/dev/null || echo "")
329-
echo "$SYSEXT_ENTITLEMENTS"
330-
if ! echo "$SYSEXT_ENTITLEMENTS" | grep -q "com.apple.developer.driverkit.transport.usb"; then
331-
echo "::warning::com.apple.developer.driverkit.transport.usb is not present in the signed system extension. Device claiming will not work."
332-
fi
333-
fi
334-
335-
# Notarize system extension bundle if notarization credentials available
336-
if [ -n "$NOTARIZATION_USERNAME" ] && [ -n "$NOTARIZATION_PASSWORD" ] && [ -d "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" ]; then
337-
echo "🔒 Notarizing system extension bundle..."
338-
339-
# Create zip for notarization (required format)
340-
ditto -c -k --keepParent "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" "$ARTIFACTS_DIR/USBIPDSystemExtension_notarization.zip"
341-
342-
# Submit for notarization with timeout
343-
echo "📤 Submitting system extension for notarization..."
344-
xcrun notarytool submit "$ARTIFACTS_DIR/USBIPDSystemExtension_notarization.zip" \
345-
--apple-id "$NOTARIZATION_USERNAME" \
346-
--password "$NOTARIZATION_PASSWORD" \
347-
--team-id "592A3U6J26" \
348-
--wait --timeout 10m || {
349-
echo "::warning::System extension notarization failed or timed out"
350-
echo "::warning::This may prevent proper System Extension installation"
351-
}
352-
353-
# Staple the notarization if successful
354-
if xcrun stapler staple "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" 2>/dev/null; then
355-
echo "✅ System extension notarization completed and stapled"
356-
else
357-
echo "::warning::Failed to staple notarization to system extension"
358-
fi
359-
360-
# Clean up notarization zip
361-
rm -f "$ARTIFACTS_DIR/USBIPDSystemExtension_notarization.zip"
362-
else
363-
echo "::warning::Notarization credentials not available - System Extension will not be notarized"
364-
echo "::warning::This will prevent proper System Extension installation on user machines"
365-
fi
366245
else
367246
echo "::warning::No code signing certificates available - binaries will be unsigned"
368247
fi
369248
370-
# Create compressed system extension bundle for release
371-
if [ -d "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension" ]; then
372-
echo "📦 Creating compressed system extension bundle..."
373-
tar -czf "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension.tar.gz" -C "$ARTIFACTS_DIR" USBIPDSystemExtension.systemextension
374-
# Remove the directory after creating the tar.gz to avoid upload conflicts
375-
rm -rf "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension"
376-
fi
377-
378249
# Create archive with all non-tar.gz files
379250
ARCHIVE_PATH="$ARTIFACTS_DIR/usbipd-mac-$VERSION.tar.gz"
380251
# Include all files except other .tar.gz files
@@ -386,9 +257,6 @@ jobs:
386257
if [ -f "$QEMU_SERVER_PATH" ]; then
387258
PATHS="$PATHS,$QEMU_SERVER_PATH"
388259
fi
389-
if [ -f "$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension.tar.gz" ]; then
390-
PATHS="$PATHS,$ARTIFACTS_DIR/USBIPDSystemExtension.systemextension.tar.gz"
391-
fi
392260
PATHS="$PATHS,$ARCHIVE_PATH"
393261
394262
echo "paths=$PATHS" >> $GITHUB_OUTPUT
@@ -441,15 +309,6 @@ jobs:
441309
CLI_SHA256=$(shasum -a 256 usbipd-${{ needs.release-validation.outputs.version }}-macos | cut -d' ' -f1)
442310
echo "CLI_SHA256=$CLI_SHA256" >> $GITHUB_ENV
443311
444-
if [ -f "USBIPDSystemExtension.systemextension.tar.gz" ]; then
445-
SYSEXT_SHA256=$(shasum -a 256 USBIPDSystemExtension.systemextension.tar.gz | cut -d' ' -f1)
446-
echo "SYSEXT_SHA256=$SYSEXT_SHA256" >> $GITHUB_ENV
447-
echo "✅ System extension checksum: ${SYSEXT_SHA256:0:16}..."
448-
else
449-
echo "SYSEXT_SHA256=" >> $GITHUB_ENV
450-
echo "⚠️ System extension bundle not found"
451-
fi
452-
453312
echo "::notice title=Checksums Generated::SHA256 checksums created for all artifacts"
454313
echo "✅ Checksums saved to $CHECKSUMS_FILE"
455314
echo "✅ CLI binary checksum: ${CLI_SHA256:0:16}..."
@@ -570,18 +429,6 @@ jobs:
570429
"generator": "usbipd-mac homebrew metadata generator v2.0"
571430
EOF
572431
573-
# Add system extension metadata if available
574-
if [ -n "${SYSEXT_SHA256:-}" ] && [ "$SYSEXT_SHA256" != "" ]; then
575-
cat >> "$METADATA_FILE" << EOF
576-
,
577-
"systemextension_url": "https://github.com/beriberikix/usbipd-mac/releases/download/$VERSION/USBIPDSystemExtension.systemextension.tar.gz",
578-
"systemextension_sha256": "$SYSEXT_SHA256"
579-
EOF
580-
echo "✅ System extension metadata included"
581-
else
582-
echo "⚠️ System extension metadata not available"
583-
fi
584-
585432
cat >> "$METADATA_FILE" << EOF
586433
},
587434
"formula_updates": {
@@ -590,15 +437,6 @@ jobs:
590437
"url_pattern": "releases/download/{{VERSION}}/usbipd-{{VERSION}}-macos"
591438
EOF
592439
593-
# Add system extension formula updates if available
594-
if [ -n "${SYSEXT_SHA256:-}" ] && [ "$SYSEXT_SHA256" != "" ]; then
595-
cat >> "$METADATA_FILE" << EOF
596-
,
597-
"sysext_sha256_placeholder": "{{SYSEXT_SHA256}}",
598-
"sysext_url_pattern": "releases/download/{{VERSION}}/USBIPDSystemExtension.systemextension.tar.gz"
599-
EOF
600-
fi
601-
602440
cat >> "$METADATA_FILE" << EOF
603441
}
604442
}
@@ -720,7 +558,6 @@ jobs:
720558
721559
This release includes the following artifacts:
722560
- **usbipd**: Main USB/IP daemon executable for macOS
723-
- **USBIPDSystemExtension.systemextension.tar.gz**: System Extension bundle for advanced USB device access
724561
- **QEMUTestServer**: QEMU integration test server (if available)
725562
- **Archive**: Complete packaged release (tar.gz)
726563
- **Checksums**: SHA256 verification checksums
@@ -736,22 +573,19 @@ jobs:
736573
\`\`\`
737574
738575
**Manual Installation:**
739-
1. Download \`usbipd-$VERSION-macos\` and \`USBIPDSystemExtension.systemextension.tar.gz\`
740-
2. Make the binary executable: \`chmod +x usbipd-$VERSION-macos\`
741-
3. Extract and install the system extension bundle
742-
4. Install the system extension: \`sudo ./usbipd-$VERSION-macos install-system-extension\`
576+
1. Download \`usbipd-$VERSION-macos-arm64\` (Apple silicon) or \`usbipd-$VERSION-macos-x86_64\` (Intel)
577+
2. Make it executable: \`chmod +x usbipd-$VERSION-macos-*\`
578+
3. Move it somewhere on your PATH
743579
744580
## Requirements
745581
746582
- macOS 11.0 or later
747583
- Administrator privileges for USB device access
748-
- System extension approval in System Preferences
749584
750585
## Notes
751586
752587
- Binaries are code-signed with Apple Developer ID when available
753-
- System extension requires user approval on first installation
754-
- Full functionality requires both the CLI binary and system extension
588+
- Devices macOS has bound a driver to are refused by \`bind\`, which names the owner
755589
EOF
756590
757591
echo "::notice title=Release Notes Ready::Release notes generated successfully"

usbipd.entitlements

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)