* chore: remove calls to DeprecatedLayoutImmediately
Replace the calls to `DeprecatedLayoutImmediately` that have test
coverage.
- The docked DevTools test added last week covers the three calls in IWCV.
- api-web-contents-view-spec covers the calls from NativeWindow{Views,Mac}.
There are a couple of remaining calls that don't have test coverage yet.
I'll get to them in a followup.
* test: handle both sync or microtask layout
* refactor: add a FlushPendingRootLayout() helper
fix: ignore draggable regions in hidden WebContentsView
Hidden child WebContentsViews were still contributing their draggable
regions to the parent window's non-client hit test, so clicks in the
area where a hidden view's draggable element would render still dragged
the window. Early-return HTNOWHERE when the view is not visible.
* build: use Yarn JsZipImpl for node-modules link step
Patch the vendored .yarn/releases/yarn-4.12.0.cjs so the node-modules
(and pnpm-loose) linker constructs its read-only ZipOpenFS with
customZipImplementation = JsZipImpl instead of the default WASM
LibZipImpl.
LibZipImpl loads each cache zip fully into the Emscripten WASM heap and
malloc's a WASM buffer per file read. With up to 80 zips held open, the
32-bit arm32v7 test container intermittently fails to allocate the ~9 MB
buffer for typescript/lib/typescript.js. Yarn's cross-FS copyFilePromise
swallows the real error and surfaces it as a generic
"EINVAL: invalid argument, copyfile", which has been failing ~1-in-3
linux-arm test shards at Install Dependencies since 2026-04-13.
JsZipImpl opens zips by fd, reads only the central directory, and pulls
individual entries into plain Node Buffers — no WASM heap involved.
There is no .yarnrc.yml or env knob for this, so the vendored release is
edited directly. .claude/README.md documents the patch and how to
re-apply it on Yarn upgrades.
Refs: yarnpkg/berry#3972, yarnpkg/berry#6722, yarnpkg/berry#6550
* docs: move JsZipImpl patch notes to .yarn/README.md
Relocate the patch rationale next to the vendored release it documents,
reword the intro for its new home, and update the header comment in
yarn-4.12.0.cjs to point at .yarn/README.md.
fix: reset printToPDF queue after a rejection
The module-scoped `pendingPromise` in `webContents.printToPDF` was chained
with `.then(onFulfilled)` and never cleared. Once a call rejected (e.g.
an out-of-range `pageRanges` like `"999"`), subsequent calls chained onto
the rejected promise and short-circuited without ever invoking
`_printToPDF` — so every following call re-surfaced the original error.
Replace the shared variable with a per-`WebContents` `WeakMap` queue that
swallows prior rejections before chaining and clears its entry once the
tail drains.
After #49428 made `NativeWindowViews::CanResize()` return `resizable_`
for frameless windows (instead of `resizable_ && thick_frame_`),
`HWNDMessageHandler::SizeConstraintsChanged()` started adding
`WS_THICKFRAME` to the window style whenever `CanResize()` reported true.
`WS_THICKFRAME` is incompatible with layered (translucent) windows and
destroys their transparency.
`SetContentSizeConstraints` already guards against this by skipping
`OnSizeConstraintsChanged()` when `!thick_frame_`. `SetResizable` did
not, so toggling resizability on a transparent window (e.g.
`setResizable(false)` then `setResizable(true)`) caused the Chromium
path to add `WS_THICKFRAME` and strip transparency.
Apply the same guard in `SetResizable`. Min/max constraints are still
enforced — Chromium reads them from the widget delegate on every
`WM_GETMINMAXINFO`, independent of `SizeConstraintsChanged()`.
* test: add Linux-specific test for getApplicationNameForProtocol()
On Linux, use XDG env vars to inject a mock that we can use
to test app.getApplicationNameForProtocol().
* fixup! test: add Linux-specific test for getApplicationNameForProtocol()
better system mocks
* fix: trigger ShipIt Mach service to unblock on-demand-only mode
When a macOS system update is pending, launchd puts the user domain
into on-demand-only mode, preventing ShipIt from starting. The
MachServices endpoint in the job dictionary was registered but never
connected to (a leftover from the XPC removal in 2013).
Instead of removing MachServices, fire a lightweight XPC connection
to the Mach port after SMJobSubmit. This satisfies launchd's
on-demand trigger, starting ShipIt immediately while preserving
KeepAlive retry behavior.
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
* fix: add ResetAtClose to ShipIt MachServices to prevent standing demand
The XPC trigger message sent after SMJobSubmit sits in the Mach port's
kernel queue unread. Without ResetAtClose, this creates standing demand
that causes launchd to respawn ShipIt after a successful exit(0),
defeating KeepAlive.SuccessfulExit = NO.
Set ResetAtClose on the MachServices registration so launchd tears down
and recreates the port when ShipIt exits, flushing the stale trigger.
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
* fix: drain Mach port before exit(0) instead of using ResetAtClose
ResetAtClose blocks KeepAlive.SuccessfulExit retries in on-demand-only
mode because it removes demand when the port resets. Instead, have
ShipIt drain its own Mach service port (via bootstrap_check_in +
mach_msg) before each exit(EXIT_SUCCESS). This clears the standing
demand from the trigger message so launchd won't respawn after a
successful exit, while leaving the message in place on failure exits
so KeepAlive retries remain demand-backed.
Tested in on-demand-only mode (pending macOS update):
- exit(0) + drain: 1 run, no respawn ✓
- exit(1) + no drain: continuous respawn every 2s ✓
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
* chore: update patch
* chore: harden ShipIt Mach trigger and simplify port drain
Scope the XPC trigger to the unprivileged path and add a send barrier
so the connection cannot be released before the message is on the wire.
Reduce drainMachServicePort to bootstrap_check_in (process exit flushes
the queue), dropping the mach_msg loop whose buffer/dealloc usage was
incorrect, and remove the no-op drain from the posix_spawn'd launch
helper. Patch filename regenerated to match the commit subject.
* fix: restore explicit mach_msg drain in drainMachServicePort
bootstrap_check_in alone does not prevent respawn: launchd tracks
outstanding demand independently of the receive right's lifetime, so the
queued trigger message must be explicitly dequeued with mach_msg before
exit(0). Verified empirically (check-in-only: 5 respawns in 10s; full
drain: 1 run). Keep the correctness fixes from the previous commit
(4K buffer, mach_msg_destroy on each receive, no mach_port_deallocate).
---------
Co-authored-by: Claude <svc-devxp-claude@slack-corp.com>
Co-authored-by: Samuel Attard <sattard@anthropic.com>
On ARM64 Windows, UnregisterSuspendResumeNotification (user32) forwards
to PowerUnregisterSuspendResumeNotification (powrprof), which treats the
HPOWERNOTIFY handle as a pointer and dereferences it. The user32 API
returns an opaque handle, not a pointer-backed allocation, causing an
access violation at shutdown.
Add crash keys (pm-reg-handle, pm-reg-memstate, pm-unreg-memstate) to
capture
- The handle value
- VirtualQuery memory state at both registration and unregistration
If the handle address is MEM_FREE, it confirms the handle is an opaque
index and powrprof is incorrectly dereferencing it. If MEM_COMMIT, it
would indicate a use-after-free of the underlying allocation.
Refs https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/powerbase/nf-powerbase-powerunregistersuspendresumenotification.md
* ci: centralize build-image SHA and pre-seed node-gyp headers
- Add .github/actions/build-image-sha as the single source of truth for
the ghcr.io/electron/build (and arch-tagged electron/test) image SHA,
with an optional override input for workflow_dispatch.
- Refactor build.yml, apply-patches.yml, build-git-cache.yml,
clean-src-cache.yml, clean-orphaned-cache-uploads.yml, and the three
publish workflows to resolve the SHA via a small ubuntu-slim setup job
instead of hardcoding it in each file.
- Bump the image to daad061f (electron/build-images#68, which pre-warms
the node-gyp header cache in the Linux images).
- Run the build.yml setup job on ubuntu-slim instead of ubuntu-latest.
- In install-dependencies (and the inline yarn installs in
pipeline-electron-lint and generate-types), link deps with
--mode=skip-build first, run `node-gyp install` with up to 3 retries
(5s backoff) to populate the header cache, then run the build phase.
This avoids the parallel-download race that intermittently fails the
first native-addon configure with an empty common.gypi on cold
macOS/Windows runners.
* ci: skip node-gyp header pre-seed on Linux
* ci: invoke node-gyp via its JS entrypoint for Windows compat
* ci: run clang-tidy on macOS and Windows
* ci: copy framework headers for clang-tidy on macOS
* chore: exclude electron_smooth_round_rect.cc in CI
* chore: C-style casts are discouraged; use static_cast [google-readability-casting]
* chore: add extra args on Windows to clear out warnings
* ci: fix for macOS --remote-build none
WebSQL support was removed in Electron 31 (see breaking-changes.md), and
the 'websql' key was subsequently removed from the storages lookup in
session.ClearStorageData() during the Chromium 126 bump (#41868).
The documentation for `ses.clearStorageData()` was not updated at the
time and still lists `websql` as a valid value for the `storages`
option. Passing `websql` now silently has no effect, leaving the docs
out of sync with the implementation.
Remove `websql` from the documented list of storage types so the
documentation matches the actual behavior.
Refs: #33900
Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
* fix: ensure corsEnabled: false protocol handlers do not work across protocols
Subresource requests for registered custom protocols are routed to
ElectronURLLoaderFactory via the renderer's per-scheme URLLoaderFactoryBundle
entry, which bypasses the network service's CorsURLLoaderFactory. This meant a
cross-origin page could fetch() a scheme registered with {supportFetchAPI: true}
and read the response body even when {corsEnabled: true} was not set.
Replicate CorsURLLoader::StartRequest's kCorsDisabledScheme gate in
ElectronURLLoaderFactory::CreateLoaderAndStart so cross-origin mode=cors
requests to such schemes fail before the JS handler runs, and tag cross-origin
mode=no-cors responses as opaque so the body is not script-readable while <img>
and similar subresource loads continue to work.
Re-enable the long-disabled "disallows CORS and fetch requests when only
supportFetchAPI is specified" test, add coverage for the opaque/no-cors,
same-origin, handler-not-invoked, corsEnabled-unaffected and net.fetch-unaffected
cases, and migrate spec helpers that were exercising a {supportFetchAPI: true}
scheme cross-origin to a corsEnabled scheme.
* chore: oxfmt
* test: strengthen layout-sensitive coverage for docked DevTools and attached WebContentsView
Improve test coverage for layout-dependent behavior by asserting geometry results:
- Test that opening right-docked DevTools shrinks the inspected page
viewport and that closing DevTools restores it.
- Test that a newly-attached WebContentsView becomes visible with a
viewport that immediately matches the window’s content bounds.
* fixup! test: strengthen layout-sensitive coverage for docked DevTools and attached WebContentsView
BUILD.gn previously hard-coded read_file(".git/packed-refs", ...) and
".git/HEAD" to derive electron_version. In a `git worktree` checkout
.git is a file containing a gitdir: pointer, not a directory, so GN's
read_file() fails and gn gen aborts unless override_electron_version is
set manually.
Ask git itself for the real locations via `git rev-parse --git-dir` /
`--git-common-dir` in a small helper script, and feed those resolved
paths to read_file() and the exec_script dependency list. Behaviour in
a plain clone is unchanged (both resolve to electron/.git/...), and the
tarball case still fails loudly with a pointer to
override_electron_version.
stop_dbus() was removed on 2025-09-14 by
99c4800e9e
I think CI isn't seeing this yet because its image has an older version.
This patched script should work on old & new versions of python-dbusmock.
* build: add chrome-release-verify and chrome-release-cls skills
Adds two project skills under .claude/skills/ for security backports:
* chrome-release-cls — given a Chrome Releases blog post URL, extract
every CVE/bug and locate the underlying Gerrit CL by searching the
local Chromium checkout and sub-repos.
* chrome-release-verify — end-to-end backport flow for a release
branch: maps CVEs→CLs, verifies which fixes are already in the synced
source tree, writes the cherry-pick patches locally, validates with
`e sync --3` + `lint --patches` (with the export→lint→re-apply loop),
then opens a single PR with the linked-CL/crbug/CVE body format.
* ci: skip platform builds for .claude/** changes
* fix: intermittent CI failure is-not-alwaysOnTop
Ensure that the `always-on-top-changed` event always fires with the
right 'alwaysOnTop' boolean, regardless of interaction between
SetZOrderLevel() and MoveBehindTaskBarIfNeeded(). We know what the
value will be when all of the HWND events settle, so use that value.
* test: temporary commit to torture-test the new change with 1000 iterations
* test: keep eventually-becomes-consistent test but do not loop 1000 times
* feat: add `Notification.getHistory()` static method (macOS)
Add `Notification.getHistory()` which returns a `Promise<Notification[]>`
of all delivered notifications still present in Notification Center.
Each returned Notification is a live object connected to the corresponding
delivered notification — interaction events (click, reply, action, close)
will fire on these objects, enabling apps to re-attach event handlers after
a restart.
Key implementation details:
- Queries UNUserNotificationCenter's getDeliveredNotifications API
- Creates live Notification objects with populated id, groupId, title,
subtitle, and body properties from what macOS provides
- Registers each object with the presenter via Restore() so the
NotificationCenterDelegate routes events correctly
- Restored notifications use is_restored_ flag to prevent removal from
Notification Center when the JS object is garbage collected
- Requires code-signed builds (unsigned builds resolve with empty array)
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
* test: fix typecheck
* fix: avoid dangling presenter pointer in GetHistory callback
* fix: document show() behavior
Notifications returned by getHistory() now set is_restored_ so that Dismiss() skips removal from Notification Center on GC. Calling show() on a restored notification removes the original from NC and posts a new one.
* fix: address code review feedback
* test: fix oxfmt linting
* docs: update docs/api/notification.md
Co-authored-by: Erick Zhao <erick@hotmail.ca>
---------
Co-authored-by: Claude <svc-devxp-claude@slack-corp.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
* ci: build a patched siso for Windows builds
The Windows Chromium builds intermittently fail during manifest load
with 'The parameter is incorrect.' (ERROR_INVALID_PARAMETER) out of
bindflt.sys. Root cause is a handle-relative NtCreateFile race in
siso/toolsupport/ninjautil/file_parser.go, which opens each subninja
twice — once in the outer goroutine and once more per chunk for
ReadAt. (*os.File).ReadAt is documented as safe for concurrent use,
so the extra open is redundant and removing it both halves the
CreateFileW calls per subninja and sidesteps the race.
Add a new build-siso-windows job on ubuntu-latest (runs in parallel
with checkout-windows) that:
- reads chromium_version from DEPS and pulls the matching siso_version
SHA from the Chromium mirror's DEPS at that ref
- shallow-clones chromium.googlesource.com/build at that SHA
- applies the in-tree patches under .github/siso-patches/ via git am
- cross-compiles siso.exe for windows/amd64
- caches the binary keyed on siso SHA + sha256 of the patches, so
subsequent runs hit the cache and skip the clone/patch/build steps
- uploads the result as a siso-windows-amd64 artifact
The Windows build jobs now depend on build-siso-windows, download the
artifact into $RUNNER_TEMP/siso, and export SISO_PATH, which
depot_tools/siso.py already honors. Mirrored into windows-publish.yml
and the regenerated pipeline-segment-electron-publish.yml so release
builds pick it up too.
Notes: none
* ci: extract siso build into a reusable workflow segment
Move the build-siso-windows job body into
pipeline-segment-build-siso-windows.yml and call it from both build.yml
and windows-publish.yml via workflow_call. Also pin actions/cache to
v5.0.5 and add version comments next to the action SHAs introduced by
this change.
fix: prevent use-after-free when destroying guest WebContents during event emission
Multiple event emission sites in WebContents destroy the underlying C++
object via a JavaScript event handler calling webContents.destroy(), then
continue to dereference the freed `this` pointer. This is exploitable
through <webview> guest WebContents because Destroy() calls `delete this`
synchronously for guests, unlike non-guests which safely defer deletion.
The fix has two layers:
1. A new `is_emitting_event_` flag is checked in Destroy() — when true,
guest deletion is deferred to a posted task instead of executing
synchronously. This is separate from `is_safe_to_delete_` (which
gates LoadURL re-entrancy) to avoid rejecting legitimate loadURL
calls from event handlers.
2. AutoReset<bool> guards on `is_emitting_event_` are added to
CloseContents, RenderViewDeleted, DidFinishNavigation, and
SetContentsBounds, preventing synchronous destruction while their
Emit() calls are on the stack.
Destroy() now requires both `is_safe_to_delete_` (navigation re-entrancy)
and `!is_emitting_event_` (event emission) to allow synchronous guest
deletion. The existing AutoReset guards on `is_safe_to_delete_` in
DidStartNavigation, DidRedirectNavigation, and ReadyToCommitNavigation
are also now effective for guests.
Because of a bug after the [upstream refactor][0] Dev Tools stopped
showing 'Electron Isolated Context' in the execution context selector.
'Electron Isolated Context' runs with origin set to `file://`. Since
domain name is empty for the origin the respective UI item in the
context selector is created with an empty `subtitle`. However, with the
upstream change items with either of `title` or `subtitle` are omitted
from rendering.
Here we float an [in-review patch][1] until it is fixed upstream.
[0]: dbb61cf4b2
[1]: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7761316