You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Release 4.5.1: streamline first successful Connect setup - #849
Based on latest at 4.5.0; no 4.6 vendor work is included.
Changes
Fresh unconfigured activation and the Plugins action lead to Connect; manual credentials move under Advanced.
Recommended setup uses a new project, generated bucket, US multi-region location and CDN mode. Existing project, bucket, location and mode controls remain under Advanced.
Same-tab, nonce-protected Google start; billing and key-custody expectations are visible.
Missing project billing has a Check again path that preserves the storage draft.
Storage drafts restore project and bucket selections after failures.
Setup runs as a job with progress on the screen. One setup at a time per site or network; a setup that is interrupted can be resumed and reuses what it already created, including its service account key.
The result of a setup, including the explanation when it fails, stays on the screen until the next action.
Service account keys do not pile up: a replaced key is revoked, a revocation that fails is retried by the next setup or a disconnect, and a disconnect names a key Google refuses to remove.
Setup state is kept with WordPress core's lock (WP_Upgrader::create_lock()) and the Options API. The only direct database calls are MySQL's named-lock functions, which are how a worker that died is noticed at once.
Privacy-limited click-to-first-upload measurement using the stateless.ci 0.3.0 broker.
WordPress.org listing: seven refreshed screenshots with new captions. .wordpress-org/ now holds every listing image, because the deploy mirrors that folder.
Privacy and security
The broker records only event timestamps, a hashed transaction ID, a hashed event token and allowlisted failure reasons that expire after seven days and are removed by the next daily cleanup. It does not record origin, email, project, bucket, OAuth codes, reusable tokens or free-form errors in funnel records. Broker-owned returned/approved/redeemed events cannot be submitted by the plugin.
OAuth callback query exclusions are active on the _Default and errors-to-bigquery log sinks. A synthetic callback was absent from logs while a non-sensitive control request remained visible. Historical logs are unchanged.
Validation
Candidate: 4.5.1-rc15 at 0f8235c. The tag tree is identical to the build that was tested (2,417 files, no differences). After the candidate only the changelog date, the release workflow reference and listing images changed (27f1fe9); no plugin code.
On the www.wpcloud.io develop-stateless test sites, all four running that build (PHP 8.5, WordPress 6.9):
19 setup scenarios against a Google stand-in on a real site, with the worker killed at chosen points: interrupted, resumed, abandoned and failed setups, key bookkeeping, disconnects, a database without lock functions
Two real processes: a second setup is refused while one runs; when the first is killed the other notices within seconds and takes over
Multisite: a sub-site keeps its records with that site, a network setup in network options
Real Google on the connected site, in a browser: a setup Google refuses keeps its explanation across reloads; a setup that succeeds keeps its result; a worker killed after its new key went live is taken over and exactly one key is left at Google; real uploads with all sizes served from the bucket
Real Google in Chrome: disconnect, new sign-in, setup with a reload afterwards, upload with all sizes, the recorded first-upload milestone, exactly one service account key
Upload and measurement fixtures, including the first-upload milestone and the multisite network case
Key-configured site: no redirect to Connect, deactivate and reactivate, media library
Ghost Inspector suite, 5 of 5 (two known screenshot baselines differ)
PHP versions, in the official php:8.1 and php:8.5 images:
Every PHP file in the package compiles on 8.1 (the declared minimum) and on 8.5
The setup test suite passes on both
Every function the plugin's own code calls exists on PHP 8.1; PHPCompatibility reports nothing new against 4.5.0
Bundled libraries are unchanged from 4.5.0
Release:
WordPress.org deploy rehearsed against the live SVN without committing: 11 plugin files change, none added or removed; seven screenshots replaced, banners and icons unchanged
publish-release.yml is back on wp-gh-release-ops.yml@master, the same workflow that published 4.5.0
Earlier candidates:
Configured CDN upgrade and multisite upgrade with settings unchanged
Broker staging regression suite (38/38)
Local:
php tests/connect-provision-job.php and node tests/connect-provision-browser.cjs
WordPress coding standards, database sniffs: no errors
Codex reviewed the complete change and follow-up fixes. Final review of 3e3f8972 reports no release-blocking correctness or security defects.
Isolated Playwright verification passed for WP admin login, deactivate/reactivate routing to Connect, same-tab start, and desktop/mobile layout. Temporary admin and local proxy were removed.
The global-Ephemeral reproduction now selects CDN. Cron/lazy cleanup, case replacement, malformed raw states, replacement races, and transaction handoff tests pass in the installed ZIP.
Configured CDN and multisite upgrades passed real upload and public HTTP 200 checks with saved settings unchanged.
The real Google OAuth/provisioning journey is still pending and is not being claimed by these checks.
Additional browser verification: an isolated Playwright session clicked Sign in with Google and landed on accounts.google.com in the same tab, with no second tab opened. No Google credentials were entered and no OAuth approval is being claimed. Activation routing and desktop/mobile layout also passed.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The Connect flow can strand users behind hidden billing requirements, inaccessible setup links, or same-tab own-client OAuth, while shared funnel state can misattribute administrators’ events.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The change hides billing recovery instructions, directs administrators to an inaccessible Connect page when setup is hidden, and can attribute OAuth events to another administrator’s attempt.
This banner also appears on unconfigured sites where Setup Assistant is explicitly hidden. In that case GoogleConnect::render_page() refuses the linked page, so an installation intentionally using manual credentials is shown a primary setup action that cannot work. Suppress this notice when GoogleConnect::hidden_for_site() is true outside network admin.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Scheduled cleanup drops the user ID, leaving abandoned sign-in records past their intended expiry, while an overly restrictive connection check can prevent network-storage uploads from recording the first-upload milestone.
Site connection blocks the network first-upload milestone
lib/classes/class-google-connect.php:608
A site-level Google connection does not mean uploads use site-level storage: Settings::refresh() applies the network bucket and credentials even when the site retains its own OAuth connection. If the site's funnel is absent or expired, this extra connection check prevents an upload using newly provisioned network storage from recording the network's first-upload milestone. Allow the fallback when no site funnel exists; the bucket comparison below already checks whether the upload uses the network bucket.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The first-upload milestone can be recorded before all image sizes finish syncing or during a no-op sync, prematurely consuming funnel state, hiding later thumbnail failures, and skewing upload measurements.
The upload milestone is now judged after the last metadata save of a request, so a size that fails after the original succeeded is reported as a failure. Media that was already in the bucket before setup started no longer counts.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Critical credential-lifecycle flaws allow disconnect/provisioning races, leave unused keys active without retryable cleanup, and overwrite working credentials with unverified keys during checkpoint resume.
The setup lock, the job record and the sign-in attempt on record were read
and written with SQL against the options tables. They are ordinary options
now, and the claim on a setup scope is core's own lock
(WP_Upgrader::create_lock). The only direct database calls left are the
three named-lock functions, which touch no table: they are how a worker
that died is noticed at once.
Also:
- a resumed setup treats a configuration entered by hand after it stopped
like any working configuration, and leaves it alone when its saved key
cannot be verified
- a disconnect first removes the keys this site still has on record at
Google; it stops with the connection kept while Google is failing, and
names a key that Google refuses to remove
- a disconnect takes the setup scope on every database, so no setup can
start while it runs
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Unresolved race conditions and stale cache or checkpoint state can erase newer sign-in tracking, overwrite completed jobs, and leave previously configured keys active after rotation.
WordPress answers repeated option reads from the copy a request already
has. The job record and the sign-in attempt on record are how requests
learn what another one did in the meantime, so they are re-read from the
database where that matters. A status check that arrives just as a setup
finishes now reports it as finished instead of interrupted, and a
long-running sync no longer removes a sign-in attempt that was saved after
it started.
Also:
- a request that takes over the scope of a worker that died records that
worker's job as interrupted
- a resumed setup puts the key it is about to replace on record, so a key
rotated by hand in between is still revoked if the resume stops as well
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Critical ownership-check gaps allow stale workers to delete a successor’s claim or disconnect cleanup to continue after lock loss, permitting overlapping setup and disconnect operations.
The check that stops a request once it no longer holds the setup scope
only applied to setup workers. It now covers every request that took the
scope, so a disconnect whose database connection was replaced stops before
it revokes or removes anything else.
A request also gives up a claim only while it is still its own: with the
database lock that is checked against the lock, and without it a claim
cannot have been taken over before it ran out, so only a younger one is
released.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because cross-tab billing rechecks can restore stale setup state, while delayed request replays can repeat project creation and billing changes.
Update at 0f8235c, published as 4.5.1-rc15. The tag tree is identical to the build that was tested.
Since 4.5.1-rc14:
Setup state no longer queries the options tables. The claim on a setup is WordPress core's lock (WP_Upgrader::create_lock()), and the job record and the sign-in attempt on record are ordinary options. The remaining direct database calls are the three MySQL named-lock functions, which touch no table.
A resumed setup leaves a configuration that was entered by hand in the meantime alone when its saved key cannot be verified, and still revokes a key that was rotated by hand.
A disconnect takes the same hold on the setup as a setup does, on every database, and is held to the same ownership check. Before it gives up access it removes the keys still on record at Google; it stops while Google is failing and names a key Google refuses to remove.
A status check that arrives just as a setup finishes reports it as finished.
WordPress.org listing images are in .wordpress-org/; screenshot 5 was re-rendered after the project count wording was corrected.
Verification on the four develop-stateless test sites running this build is listed in the description. All review threads are resolved; the one declined suggestion (a single-statement compare-and-delete for the measurement record) is answered in its thread.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Critical credential-lifecycle gaps can leave issued Google keys untracked or revoke the site’s live key, while expired nonces can trap setup in endless polling.
GitHub: tag 4.5.1 at 5b109e7. Its tree is the tested candidate (4.5.1-rc15) plus the changelog date and the listing images; no plugin code differs.
WordPress.org: r3797565. 11 plugin files changed, none added or removed, and seven screenshots replaced. The zip WordPress.org serves is identical to the tag's plugin files.
The points from the last two review rounds are answered in their threads and planned for the next patch release.
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
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.
Based on
latestat 4.5.0; no 4.6 vendor work is included.Changes
WP_Upgrader::create_lock()) and the Options API. The only direct database calls are MySQL's named-lock functions, which are how a worker that died is noticed at once..wordpress-org/now holds every listing image, because the deploy mirrors that folder.Privacy and security
The broker records only event timestamps, a hashed transaction ID, a hashed event token and allowlisted failure reasons that expire after seven days and are removed by the next daily cleanup. It does not record origin, email, project, bucket, OAuth codes, reusable tokens or free-form errors in funnel records. Broker-owned returned/approved/redeemed events cannot be submitted by the plugin.
OAuth callback query exclusions are active on the
_Defaultanderrors-to-bigquerylog sinks. A synthetic callback was absent from logs while a non-sensitive control request remained visible. Historical logs are unchanged.Validation
Candidate: 4.5.1-rc15 at 0f8235c. The tag tree is identical to the build that was tested (2,417 files, no differences). After the candidate only the changelog date, the release workflow reference and listing images changed (27f1fe9); no plugin code.
On the
www.wpcloud.iodevelop-stateless test sites, all four running that build (PHP 8.5, WordPress 6.9):PHP versions, in the official
php:8.1andphp:8.5images:Release:
publish-release.ymlis back onwp-gh-release-ops.yml@master, the same workflow that published 4.5.0Earlier candidates:
Local:
php tests/connect-provision-job.phpandnode tests/connect-provision-browser.cjs