Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
134 lines
6.0 KiB
JavaScript
134 lines
6.0 KiB
JavaScript
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
// The environment a Maka fixture window launches into.
|
|
//
|
|
// Extracted from apps/desktop/e2e/fixtures.ts, which worked it out first and
|
|
// remains a consumer. Two things now launch fixture windows — the Playwright
|
|
// E2E suite and the migration contract harness in scripts/ — and both need the
|
|
// same isolation, so the rule lives in one place instead of being restated
|
|
// (and, as the harness proved, restated wrongly).
|
|
|
|
/**
|
|
* Keys deleted from the inherited environment before launch.
|
|
*
|
|
* Deny-list rather than allow-list: Electron relies on undocumented platform
|
|
* env (macOS CoreFoundation / X11 / sandbox session) that an allow-list would
|
|
* silently drop and break the launch.
|
|
*
|
|
* Inheriting `process.env` wholesale leaks:
|
|
* - provider keys, which auto-bootstrap a connection and change the fixture;
|
|
* - `VITE_DEV_SERVER_URL`, which loads the dev server instead of the built
|
|
* bundle — so the run silently measures something other than the build
|
|
* under test;
|
|
* - any `MAKA_E2E_*` the operator's shell happens to export, which silently
|
|
* changes locale, platform, theme, or window visibility.
|
|
* @param {string} key
|
|
*/
|
|
function isDeniedEnvKey(key) {
|
|
return (
|
|
key === 'VITE_DEV_SERVER_URL' ||
|
|
key.startsWith('MAKA_E2E') ||
|
|
/_API_KEY$/.test(key) ||
|
|
/_API_TOKEN$/.test(key) ||
|
|
/_API_SECRET$/.test(key)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param {string} userDataDir
|
|
* @param {string} homeDir
|
|
* @param {{
|
|
* scenario?: string,
|
|
* locale?: 'zh' | 'en',
|
|
* platform?: 'darwin' | 'win32' | 'linux',
|
|
* theme?: 'light' | 'dark',
|
|
* scrollMotion?: 'auto' | 'smooth',
|
|
* timezone?: string,
|
|
* showWindow?: boolean,
|
|
* }} [options]
|
|
* @returns {NodeJS.ProcessEnv}
|
|
*/
|
|
export function buildFixtureEnv(userDataDir, homeDir, options = {}) {
|
|
const env = { ...process.env };
|
|
for (const key of Object.keys(env)) {
|
|
if (isDeniedEnvKey(key)) delete env[key];
|
|
}
|
|
env.MAKA_E2E = '1';
|
|
// The login-shell PATH probe must not make command resolution depend on the
|
|
// developer or CI account. This builder owns the launched environment, so it
|
|
// owns the deterministic skip flag (unlike relying on TERM, which is unset
|
|
// under xvfb).
|
|
env.MAKA_SKIP_SHELL_ENV = '1';
|
|
env.MAKA_E2E_USER_DATA_DIR = userDataDir;
|
|
// Sandbox the home directory. User-scope skill discovery reads
|
|
// `~/.maka/skills` and `~/.agents/skills` via `os.homedir()`, and the Skills
|
|
// panel can now DELETE from those (#1517) — so without this a run would
|
|
// enumerate, and could remove, the developer's own installed skills.
|
|
// Overriding HOME sandboxes every consumer of the home dir at once, rather
|
|
// than plumbing an override through each skills API and hoping none is
|
|
// missed; `os.homedir()` returns $HOME on POSIX and %USERPROFILE% on
|
|
// Windows, so both are set. userData is pinned separately above, so this
|
|
// does not move the app's data dir.
|
|
env.HOME = homeDir;
|
|
env.USERPROFILE = homeDir;
|
|
if (options.scenario) env.MAKA_E2E_FIXTURE = options.scenario;
|
|
if (options.locale) env.MAKA_E2E_FIXTURE_LOCALE = options.locale;
|
|
if (options.platform) env.MAKA_E2E_FIXTURE_PLATFORM = options.platform;
|
|
if (options.theme) env.MAKA_E2E_FIXTURE_THEME = options.theme;
|
|
// Absolute times render through the host zone, so a capture taken in
|
|
// Asia/Shanghai reads as a diff when the same build is captured in UTC. The
|
|
// fixture already owns an IANA override for exactly this; callers that
|
|
// compare captures pin it, and the E2E suite does not, because its
|
|
// assertions never read a wall-clock string.
|
|
if (options.timezone) env.MAKA_E2E_FIXTURE_TIMEZONE = options.timezone;
|
|
// Windows launch hidden so a run never steals the developer's focus; a
|
|
// caller that needs the compositor (hit testing, real input) or a throttled
|
|
// headless display (see isCiLinuxDisplay) asks for a visible window
|
|
// explicitly. The decision stays with the caller: this builder is a pure
|
|
// function of its arguments, so a test asserting "hidden run stays hidden"
|
|
// means the same thing on a laptop and on a CI runner.
|
|
// Captures collapse scroll motion so their state never depends on when a
|
|
// scroll settles. A fixture whose subject IS the scrolling asks for the
|
|
// production behavior back — see `scroll-motion-policy`. Per launch rather
|
|
// than per scenario: it costs several seconds of settling per window, and
|
|
// only the case that needs it should pay.
|
|
if (options.scrollMotion) env.MAKA_E2E_FIXTURE_SCROLL_MOTION = options.scrollMotion;
|
|
if (options.showWindow) env.MAKA_E2E_SHOW_WINDOW = '1';
|
|
return env;
|
|
}
|
|
|
|
/**
|
|
* Whether the current host is a Linux CI display, where a fixture window must
|
|
* be shown even for captures: under xvfb a hidden window's compositor is
|
|
* throttled to ~1fps — content-visibility turns never inflate and frame-paced
|
|
* protocols crawl. Only that isolated virtual display gets a visible window;
|
|
* nobody is watching it.
|
|
*
|
|
* This is the one ambient read the launch environment needs, kept out of
|
|
* `buildFixtureEnv` so the builder stays a pure function. Callers compose it:
|
|
* `showWindow: wantVisible || isCiLinuxDisplay()`.
|
|
*
|
|
* @param {NodeJS.ProcessEnv} [env]
|
|
* @param {NodeJS.Platform} [platform]
|
|
*/
|
|
export function isCiLinuxDisplay(env = process.env, platform = process.platform) {
|
|
return Boolean(env.CI) && platform === 'linux';
|
|
}
|