fix(macos): validate PID and socket before reporting window as minimized

- Move PID extraction and app PID match before minimized check in windowStateFromAccessibilityAPI
- Add test asserting correct validation order in get-mpv-window-macos.swift
- Include new test in test:fast suite
This commit is contained in:
2026-05-15 18:58:42 -07:00
parent b9ca198039
commit 44609f3da0
3 changed files with 45 additions and 8 deletions
+1 -1
View File
@@ -70,7 +70,7 @@
"test:launcher": "bun run test:launcher:src",
"test:core": "bun run test:core:src",
"test:subtitle": "bun run test:subtitle:src",
"test:fast": "bun run test:config:src && bun run test:core:src && bun run test:docs:kb && bun test src/main-entry-runtime.test.ts src/anki-integration.test.ts src/anki-integration/card-creation-manual-update.test.ts src/anki-integration/anki-connect-proxy.test.ts src/anki-integration/field-grouping-workflow.test.ts src/anki-integration/field-grouping.test.ts src/anki-integration/field-grouping-merge.test.ts src/release-workflow.test.ts src/prerelease-workflow.test.ts src/ci-workflow.test.ts scripts/build-changelog.test.ts scripts/electron-builder-after-pack.test.ts scripts/mkv-to-readme-video.test.ts scripts/run-coverage-lane.test.ts scripts/update-aur-package.test.ts && bun test src/core/services/immersion-tracker/__tests__/query.test.ts src/core/services/immersion-tracker/__tests__/query-split-modules.test.ts && bun run tsc && bun test dist/main/runtime/registry.test.js",
"test:fast": "bun run test:config:src && bun run test:core:src && bun run test:docs:kb && bun test src/main-entry-runtime.test.ts src/anki-integration.test.ts src/anki-integration/card-creation-manual-update.test.ts src/anki-integration/anki-connect-proxy.test.ts src/anki-integration/field-grouping-workflow.test.ts src/anki-integration/field-grouping.test.ts src/anki-integration/field-grouping-merge.test.ts src/release-workflow.test.ts src/prerelease-workflow.test.ts src/ci-workflow.test.ts scripts/build-changelog.test.ts scripts/electron-builder-after-pack.test.ts scripts/get-mpv-window-macos.test.ts scripts/mkv-to-readme-video.test.ts scripts/run-coverage-lane.test.ts scripts/update-aur-package.test.ts && bun test src/core/services/immersion-tracker/__tests__/query.test.ts src/core/services/immersion-tracker/__tests__/query-split-modules.test.ts && bun run tsc && bun test dist/main/runtime/registry.test.js",
"generate:config-example": "bun run src/generate-config-example.ts",
"verify:config-example": "bun run src/verify-config-example.ts",
"start": "bun run build && electron . --start",
+11 -7
View File
@@ -174,22 +174,26 @@ private func windowStateFromAccessibilityAPI() -> WindowLookupResult? {
}
for window in windows {
var minimizedRef: CFTypeRef?
let minimizedStatus = AXUIElementCopyAttributeValue(window, kAXMinimizedAttribute as CFString, &minimizedRef)
if minimizedStatus == .success, let minimized = minimizedRef as? Bool, minimized {
foundMinimizedTargetWindow = true
continue
}
var windowPid: pid_t = 0
if AXUIElementGetPid(window, &windowPid) != .success {
continue
}
if windowPid != app.processIdentifier {
continue
}
if !windowHasTargetSocket(windowPid) {
continue
}
var minimizedRef: CFTypeRef?
let minimizedStatus = AXUIElementCopyAttributeValue(window, kAXMinimizedAttribute as CFString, &minimizedRef)
if minimizedStatus == .success, let minimized = minimizedRef as? Bool, minimized {
foundMinimizedTargetWindow = true
continue
}
if let geometry = geometryFromAXWindow(window) {
return .visible(
WindowState(
+33
View File
@@ -0,0 +1,33 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';
const source = readFileSync('scripts/get-mpv-window-macos.swift', 'utf8');
test('minimized Accessibility windows are validated by PID and socket before reporting minimized', () => {
const minimizedAssignmentIndex = source.indexOf('foundMinimizedTargetWindow = true');
assert.notEqual(minimizedAssignmentIndex, -1);
const loopStartIndex = source.lastIndexOf('for window in windows', minimizedAssignmentIndex);
assert.notEqual(loopStartIndex, -1);
const pidExtractionIndex = source.indexOf(
'AXUIElementGetPid(window, &windowPid)',
loopStartIndex,
);
const appPidMatchIndex = source.indexOf('windowPid != app.processIdentifier', loopStartIndex);
const socketCheckIndex = source.indexOf('if !windowHasTargetSocket(windowPid)', loopStartIndex);
assert.ok(
pidExtractionIndex > loopStartIndex && pidExtractionIndex < minimizedAssignmentIndex,
'window PID must be extracted before accepting a minimized window',
);
assert.ok(
appPidMatchIndex > pidExtractionIndex && appPidMatchIndex < minimizedAssignmentIndex,
'window PID must match the owning app before accepting a minimized window',
);
assert.ok(
socketCheckIndex > appPidMatchIndex && socketCheckIndex < minimizedAssignmentIndex,
'target socket must be validated before accepting a minimized window',
);
});