feat(plugins): let notarized third-party plugins install after you trust their developer - #2212
Merged
Conversation
…ust their developer
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
PluginCodeSignatureVerifierrequired every plugin bundle to be signed by TablePro's own Apple team:with seven call sites and a DEBUG-only bypass. So a driver could only ever be published by the maintainers. It had to live under
Plugins/in this repo, be declared inproject.yml, get a hand-written arm inbuild-plugin.yml, and be tagged here. Eight of the open issues areDatabase request:and none of them can be served by anyone else.The registry README told contributors to "code-sign it with a valid Apple Developer certificate", which does not work: their Developer ID carries their team OU, not TablePro's, so the bundle is rejected at load time with "Bundle failed to load executable". Anyone who followed those instructions built something the app refuses to open. That README is fixed separately in TableProApp/plugins#5.
The evidence that the gate is the binding constraint, rather than a lack of interest, is a natural experiment this project already ran on itself. The
linuxbranch has five Rust driver crates and no signing gate. Two outside contributors, with 4 and 2 lifetime commits between them, landed three drivers there in six weeks. The macOS registry, with the gate, has had zero third-party plugins ever.What changes
A bundle now resolves to one of three outcomes instead of pass or fail:
Trust is recorded per Apple Team ID rather than per plugin, so a developer's later plugins and updates install without asking again, and revoking one developer stops every plugin they signed. The team ID is assigned by Apple and cannot be chosen by the signer, so two developers can never collide and a rename cannot move trust between them.
The prompt says what is actually being granted: a driver runs as part of TablePro and can read the credentials of every connection you open.
Why this is safe
SecStaticCodeCheckValidityperforms notarization checks by default.kSecCSNoNetworkAccessis the flag that turns them off, and a bundle whose notarization Apple revoked fails witherrSecCSRevokedNotarization. So a Developer ID bundle that gets as far as the prompt is one Apple has seen and has not revoked.The Developer ID requirement string uses
1.2.840.113635.100.6.1.13, Apple's Developer ID Application marker OID. That was verified rather than recalled:codesign -Ragainst a real Developer ID signed app on disk matches it, and the same app fails TablePro's existing team-OU requirement.Every call site is covered, and they are deliberately not all the same:
PluginManager) and the validation helper enforce trust and never prompt, so revoking a developer stops their plugins loading on the next launch.Notes
PluginDeveloperTrustStoreis deliberately not@MainActor, unlikeExternalConnectionTrustStorewhich it otherwise mirrors. The plugin load path runs off the main actor and has to read trust before loading a bundle; the store wrapsUserDefaultsand holds no other state.Themes are untouched. They are JSON with no executable, go through
ThemeRegistryInstallerrather than this path, and are verified by SHA-256 against the manifest.What this does not do
TableProPluginKit still ships inside this repository rather than as a versioned XCFramework, so a third-party driver still has to build against a checkout. That is the next step, and it is independent of this one.
Verification
buildPASStestPluginDeveloperTrustStoreTests, PluginSignatureTrustTestslint TablePro