收口桌面壳JS依赖边界

移除根H5与桌面壳未使用的Tauri JS guest依赖

新增桌面壳检查,禁止根包和桌面壳包安装Tauri JS guest包

更新原生壳方案和共享决策记录,明确桌面系统能力只由Rust HostBridge分发
This commit is contained in:
2026-06-18 12:30:43 +08:00
parent ef5b7afd2c
commit 6a5869596c
6 changed files with 37 additions and 40 deletions
-4
View File
@@ -8,10 +8,6 @@
"build": "tauri build",
"typecheck": "node scripts/check-config.mjs"
},
"dependencies": {
"@tauri-apps/api": "^2.11.0",
"@tauri-apps/plugin-opener": "^2.5.0"
},
"devDependencies": {
"@tauri-apps/cli": "^2.11.2",
"typescript": "~5.8.2"
@@ -4,6 +4,8 @@ const configPath = new URL('../src-tauri/tauri.conf.json', import.meta.url);
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
const packagePath = new URL('../package.json', import.meta.url);
const packageConfig = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
const rootPackagePath = new URL('../../../package.json', import.meta.url);
const rootPackageConfig = JSON.parse(fs.readFileSync(rootPackagePath, 'utf8'));
const capabilityPath = new URL(
'../src-tauri/capabilities/main.json',
import.meta.url,
@@ -136,6 +138,29 @@ function assertNoBlockedNpmDependencies() {
}
}
function collectNpmDependencyNames(packageJson) {
const dependencySections = [
'dependencies',
'devDependencies',
'optionalDependencies',
'peerDependencies',
];
return dependencySections.flatMap((section) =>
Object.keys(packageJson[section] ?? {}),
);
}
function assertNoTauriGuestNpmDependencies(packageJson, packageLabel) {
for (const dependency of collectNpmDependencyNames(packageJson)) {
if (dependency === '@tauri-apps/api' || dependency.startsWith('@tauri-apps/plugin-')) {
throw new Error(
`${packageLabel} must not depend on ${dependency}; desktop H5 must use HostBridge through the injected Tauri global only`,
);
}
}
}
function assertNoBlockedCargoDependencies() {
for (const dependency of blockedDesktopCargoDependencies) {
const dependencyPattern = new RegExp(
@@ -220,6 +245,8 @@ assertNoDevScaffoldTerms(
productionSourceRoots.flatMap((root) => collectProductionSourceFiles(root)),
);
assertNoBlockedNpmDependencies();
assertNoTauriGuestNpmDependencies(packageConfig, 'desktop shell package');
assertNoTauriGuestNpmDependencies(rootPackageConfig, 'root H5 package');
assertNoBlockedCargoDependencies();
assertNoBlockedDesktopSdkSnippets();
@@ -2376,3 +2376,10 @@
- 决策:移动壳配置门禁固定 Expo `name``slug``userInterfaceStyle``assetBundlePatterns``extra.genarrativeHostBridgeVersion`,并要求 Android 默认 `permissions` 为空,只通过 `blockedPermissions` 阻断当前不需要的高风险权限;`apps/mobile-shell/scripts/check-config.mjs` 检查源 `app.json``apps/mobile-shell/scripts/check-expo-config.mjs` 检查 Expo CLI 最终解析出的 public config,防止 config plugin 或解析阶段引入身份、资源或权限漂移。新增权限必须先有真实宿主能力、系统权限说明和 H5 fallback。桌面壳配置门禁固定唯一 `label=main` 主窗口,`src-tauri/capabilities/` 只能存在 `main.json`,且该 capability 只能绑定 `windows=["main"]``permissions=["core:default","allow-host-bridge-request"]`,继续只暴露 `host_bridge_request` 一个受控入口。
- 影响范围:`apps/mobile-shell/scripts/check-config.mjs``apps/mobile-shell/scripts/check-expo-config.mjs``apps/desktop-shell/scripts/check-config.mjs`、Expo / Tauri HostBridge 方案文档。
- 验证方式:`npm run check:native-shells``npm run typecheck``npm run check:encoding``git diff --check`
## 2026-06-18 桌面壳 JS guest 依赖收口
- 背景:Tauri 桌面壳的生产前端实际只通过 `HostBridge` 和注入的 `window.__TAURI__.core.invoke('host_bridge_request')` 与 Rust 通信;如果根 H5 包或桌面壳包安装 `@tauri-apps/api` / `@tauri-apps/plugin-*` JS 客户端包,后续容易绕过唯一 command 与 capability 边界。
- 决策:根 H5 `package.json``apps/desktop-shell/package.json` 不安装 `@tauri-apps/api` 或任何 `@tauri-apps/plugin-*` JS guest 包;opener、clipboard、dialog、notification 等桌面系统能力只保留 Rust Cargo 插件,由 `host_bridge_request` 内部分发。`apps/desktop-shell/scripts/check-config.mjs` 对两个 package 都做依赖门禁,Tauri CLI 仅作为构建工具保留。
- 影响范围:根依赖、桌面壳依赖、桌面壳配置检查和 Expo / Tauri HostBridge 方案文档。
- 验证方式:`npm run check:native-shells``npm run typecheck``npm run check:encoding``git diff --check`
@@ -182,6 +182,7 @@ Tauri 壳同样只负责桌面宿主能力,不承接玩法业务。
- 主 WebView 默认拒绝网页自动下载或 `<a download>` 触发的落盘动作;用户保存文本、图片、音频等内容必须走已声明的 `file.exportText``file.exportImage``file.exportAudio` HostBridge method,由 Rust 侧执行 MIME、大小、文件名清洗和系统保存对话框确认。
- 主 WebView 显式关闭 DevToolsCargo 不启用 Tauri `devtools` feature;本地调试通过普通浏览器和 Vite 完成,不把可分发桌面壳变成调试容器。
- 崩溃上报、前端 analytics、桌面遥测日志、自动更新和渠道分发 SDK 都必须等真实端点、采集字段、用户同意、隐私策略、签名和发布流程确定后逐项接入;当前桌面壳不安装 Sentry、Datadog、PostHog、Segment、Amplitude、Bugsnag、OpenTelemetry、Tauri log / updater 等相关依赖。
- 桌面壳和根 H5 包不安装 `@tauri-apps/api``@tauri-apps/plugin-*` JS guest 包;生产 H5 只通过 Tauri 注入的 `window.__TAURI__.core.invoke('host_bridge_request', request)` 进入 HostBridge。opener、clipboard、dialog、notification 等能力只保留 Rust Cargo 插件,由 Rust 内部分发并受 capability 白名单约束。
桌面 release 和 dev 模式:
@@ -342,6 +343,8 @@ GameBridge 禁止:
2026-06-18 追加:桌面壳 capability 作用域进入配置门禁。Tauri 配置只能声明一个 `label=main` 的主窗口,`src-tauri/capabilities/` 只能存在 `main.json`,该 capability 的 `identifier` 必须为 `main``windows` 必须只包含 `main``permissions` 必须只包含 `core:default``allow-host-bridge-request`。这保证 opener、clipboard、dialog、notification 等插件只由 Rust 内部通过受控 HostBridge 分发使用,不把插件 JS guest API 或额外窗口权限授给 H5 主站。
2026-06-18 追加:桌面壳 JS guest 依赖进入门禁。`apps/desktop-shell/package.json` 和根 H5 `package.json` 不得安装 `@tauri-apps/api` 或任何 `@tauri-apps/plugin-*` 包,避免生产前端绕过 `nativeAppHostBridge` 直接调用 Tauri JS 客户端 APITauri CLI 仍只作为构建工具留在 devDependencies,桌面系统能力继续由 Rust 侧 Cargo 插件和唯一 `host_bridge_request` command 承接。
2026-06-18 追加:桌面壳 release CSP 与 dev CSP 分离。Release `csp` 不再包含 `http://127.0.0.1:*``ws://127.0.0.1:*`,只允许打包资产、自身脚本、生产 HTTPS / WSS API、图片、媒体和 sandbox frame 所需来源;本地 Vite、HMR WebSocket 和开发 frame 只写入 Tauri `devCsp``apps/desktop-shell/scripts/check-config.mjs` 会拒绝 release CSP 混入本机调试源,也会校验 dev CSP 仍保留本机开发源。
2026-06-18 追加:桌面壳 release 构建烟测进入统一验收。`npm run check:native-shells` 会在 H5 HostBridge、Expo 壳和 Tauri 单测通过后执行 `npm run desktop-shell:build -- --no-bundle`,确认根 `dist` H5 资产、Tauri release 入口、受控命令白名单、图标和 Rust release 编译可以共同产出桌面二进制;该烟测不生成平台安装包,避免把 Linux 本机缺少的系统打包器误判为 HostBridge 回归。
-34
View File
@@ -10,8 +10,6 @@
"dependencies": {
"@expo/metro-runtime": "^56.0.15",
"@tailwindcss/vite": "^4.1.14",
"@tauri-apps/api": "^2.11.0",
"@tauri-apps/plugin-opener": "^2.5.4",
"@vitejs/plugin-react": "^5.0.4",
"cannon-es": "^0.20.0",
"dotenv": "^17.2.3",
@@ -3677,16 +3675,6 @@
"vite": "^5.2.0 || ^6 || ^7 || ^8"
}
},
"node_modules/@tauri-apps/api": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.0.tgz",
"integrity": "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==",
"license": "Apache-2.0 OR MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tauri"
}
},
"node_modules/@tauri-apps/cli": {
"version": "2.11.2",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.2.tgz",
@@ -3904,15 +3892,6 @@
"node": ">= 10"
}
},
"node_modules/@tauri-apps/plugin-opener": {
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.4.tgz",
"integrity": "sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.11.0"
}
},
"node_modules/@testing-library/dom": {
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
@@ -15542,11 +15521,6 @@
"tailwindcss": "4.2.2"
}
},
"@tauri-apps/api": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.0.tgz",
"integrity": "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA=="
},
"@tauri-apps/cli": {
"version": "2.11.2",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.2.tgz",
@@ -15643,14 +15617,6 @@
"dev": true,
"optional": true
},
"@tauri-apps/plugin-opener": {
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.4.tgz",
"integrity": "sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==",
"requires": {
"@tauri-apps/api": "^2.11.0"
}
},
"@testing-library/dom": {
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
-2
View File
@@ -82,8 +82,6 @@
"dependencies": {
"@expo/metro-runtime": "^56.0.15",
"@tailwindcss/vite": "^4.1.14",
"@tauri-apps/api": "^2.11.0",
"@tauri-apps/plugin-opener": "^2.5.4",
"@vitejs/plugin-react": "^5.0.4",
"cannon-es": "^0.20.0",
"dotenv": "^17.2.3",