Repository navigation
Accept the key as the HTTP Basic password on the Composer routes - #7
Conversation
Dependabot's composer-repository registry can only send a username and password, so its Composer jobs could not reach reason-dev/* packages once SIMPLE_UPDATE_KEY was enforced. Any username is accepted; the password must equal the key. Bearer is unchanged; the query string is still refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LzLdtrTXNxMS97RQ7NiMLh
There was a problem hiding this comment.
I reviewed this PR and didn't find any bugs. It widens what counts as a valid credential on the key-protected Composer routes, so a human look is still worthwhile before it merges.
What was reviewed:
isAuthorized()in includes/Wpup/ComposerRepository.php: Bearer handling is unchanged. Basic uses strict base64 decoding, requires a colon, splits on the first colon only (so a password containing:still works), and compares the password withhash_equals. Any other scheme or a non-string header is rejected.- The Basic header should reach the code under the Bref php-84-fpm runtime, because Wpup_Headers reads
HTTP_*keys from$_SERVER. - The new tests cover the accept and reject cases. The runbook adds the Dependabot secret-store rotation step.
Extended reasoning...
The change touches authentication on the Composer routes (/packages.json, /p2, /dist). It now accepts SIMPLE_UPDATE_KEY as an HTTP Basic password with any username, alongside the existing Bearer token. The rest of the PR adds tests and runbook documentation. The code is small, follows the existing hash_equals pattern and has good tests, and no bugs were found. It still changes which credentials the auth check accepts, so per the approval guidelines a human should confirm the change rather than having it auto-approved.
Summary
The Composer routes (
/packages.json,/p2/…,/dist/…) now also accept the update key as the password in HTTP Basic auth, with any username. Bearer works exactly as before, and the key is still never accepted from the query string.Why
No Asana task.
SIMPLE_UPDATE_KEYis now enforced in production. Dependabot'scomposerjobs in plugin and theme repos (for example reason-dot-com-theme) resolvereason-dev/*packages from packages.reason.com. Dependabot'scomposer-repositoryregistry can only sendusernameandpassword, with no token option (options reference), so those jobs now get a 401 every time. Plugin CI and site image builds are unaffected; they already send Bearer.Changes
includes/Wpup/ComposerRepository.php:isAuthorized()acceptsBearer <key>(unchanged) orBasic base64(<user>:<key>). The username is ignored. The password is compared to the key withhash_equals, as for Bearer. Base64 is decoded strictly, a value with no:is refused, and any other scheme is refused. The class docblock says so. TheWWW-Authenticate: Bearerchallenge is unchanged.tests/composer-repository-test.php: the oldbasic scheme: 401check is replaced by checks for Basic with the key as the password (200), an empty username (200), a lowercase scheme (200), a wrong password, the key as the username, no colon, extra text after the key, non-base64, thedistroute, and an unknown scheme (all 401).docs/runbook.md: the routes section mentions Basic, and the rotation step for the org secret now says it lives in both the Actions and the Dependabot secret stores. A new "Dependabot in plugin and theme repos" section gives theregistriesblock to copy.Alternatives considered
composerupdates in those repos. Rejected: it gives up automated update PRs forreason-dev/*and third-party Composer dependencies alike.composer.lock.Testing
php tests/composer-repository-test.phpandphp tests/index-routing-test.php: all pass (exit 0).ComposerRepository.phpreverted, the three "Basic should be accepted" checks fail. So the new tests do exercise the change.php -lon the changed class: clean.Review: self-review by @justinmaurerdotdev (repo admin)
Not in this PR
curl -s -o /dev/null -w '%{http_code}' -u "x:$KEY" https://packages.reason.com/packages.jsonshould print 200.registriesblock in each repo'sdependabot.yml: follow-up PRs after this is deployed.🤖 Generated with Claude Code
https://claude.ai/code/session_01LzLdtrTXNxMS97RQ7NiMLh