Build paid plugins individually with each owner's GitHub token#404
Merged
Conversation
A full Satis rebuild (satis:build with no --plugin) sent every paid plugin in one request with a single shared GitHub token. A satis build can only authenticate to github.com as one identity, but paid plugins live in private repos across different owners/orgs, so one token can't clone them all — the rest fall back to unauthenticated requests and hit the 60/hour rate limit. With satis's --skip-errors that produced a near-empty, authoritative rebuild that wiped packages.json. buildAll() now iterates and builds each approved paid plugin individually using its owner's GitHub token (resolved via ResolvesGitHubToken). These are partial, merging builds on the satis side, so a single failure never overwrites the published index with an incomplete set. - Refactor ResolvesGitHubToken to expose resolveGitHubTokenFor(Plugin); SatisService uses it. - Add SatisService::buildForPlugin(); the satis:build --plugin path now uses the owner's token too. - Update the command to report per-plugin dispatch results; update the buildAll test (per-plugin partial builds, full_build === false). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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.
Problem
A full Satis rebuild (
php artisan satis:buildwith no--plugin) sent every paid plugin in a single request using one shared GitHub token. A satis build can only authenticate togithub.comas one identity, but paid plugins live in private repos across different owners/orgs — so one token can't clone them all and the rest fall back to unauthenticated requests, hitting GitHub's 60/hour rate limit. Combined with satis's--skip-errors, the build "succeeded" with most repos skipped and authoritatively overwrotepackages.jsonwith a near-empty index.(Per-plugin syncs via
SyncPluginReleasesalready used the owner's token, so only the full-rebuild path was affected.)Changes
buildAll()now builds each approved paid plugin individually, using its owner's GitHub token (resolved viaResolvesGitHubToken). Each is a partial, merging build on the satis side, so a single failure can never overwrite the published index with an incomplete set. Returns a per-plugin summary (plugins_count,failed,results).ResolvesGitHubTokento exposeresolveGitHubTokenFor(Plugin)(the existinggetGitHubToken()delegates to it, behaviour unchanged);SatisServicenow uses the trait.SatisService::buildForPlugin()— resolve owner token + build one plugin. Thesatis:build --pluginpath now uses it too (previously it sent no token).satis:buildcommand reports per-plugin dispatch results.buildAllnow sends one partial build per paid plugin (full_build === false), asserted viaHttp::assertSentCount(1).Note
This is the root-cause fix; the companion guard in plugins.nativephp.com (NativePHP/plugins.nativephp.com#7) refuses to publish an incomplete full build as defense-in-depth. Paid plugins whose owner has not connected GitHub still fall back to
config('services.github.token')(GITHUB_TOKEN), which is currently unset and not in.env.example— worth setting. The long-term fix is the GitHub App (in progress separately).Testing
php artisan test tests/Feature/SatisSync/SatisSyncTest.php tests/Feature/Jobs/SyncPluginReleasesTest.php→ 11 passed.php -land Pint clean on changed files.🤖 Generated with Claude Code