锁定移动文件分享不可用边界

移动文件导出测试覆盖文本图片音频分享不可用时不写缓存

移动壳配置检查反查文件导出不可用不伪成功断言

共享决策日志补充移动文件导出分享不可用边界
This commit is contained in:
2026-06-20 10:22:42 +08:00
parent 15faa50992
commit d967b9cea0
3 changed files with 30 additions and 7 deletions
@@ -2042,6 +2042,9 @@ for (const snippet of [
'describe(\'mobile HostBridge file actions\'',
'exportTextFile({',
'exportImageFile({',
'rejects every export before cache writes when system sharing is unavailable',
'const exportCases = [',
'expect(writtenFiles).toHaveLength(0)',
'importTextFile()',
'importDocumentFile()',
'importAudioFile()',
@@ -141,18 +141,37 @@ describe('mobile HostBridge file actions', () => {
});
});
test('rejects exports when system sharing is unavailable', async () => {
test('rejects every export before cache writes when system sharing is unavailable', async () => {
shareAvailableMock.mockResolvedValue(false);
await expect(
exportImageFile({
const exportCases = [
() =>
exportTextFile({
content: '泥巴AI',
fileName: '创作记录',
mimeType: 'text/plain',
}),
() =>
exportImageFile({
base64Data: PNG_BASE64,
fileName: '分享卡',
mimeType: 'image/png',
}),
).rejects.toMatchObject({
code: 'unsupported_capability',
});
}),
() =>
exportAudioFile({
base64Data: MP3_BASE64,
fileName: '声浪',
mimeType: 'audio/mpeg',
}),
];
for (const exportFile of exportCases) {
await expect(exportFile()).rejects.toMatchObject({
code: 'unsupported_capability',
});
}
expect(writtenFiles).toHaveLength(0);
expect(shareAsyncMock).not.toHaveBeenCalled();
});
@@ -41,6 +41,7 @@
- 2026-06-19 桌面壳文件桥接执行边界:Tauri `file.exportText` / `file.importText` / `file.importDocument` / `file.exportImage` / `file.importImage` / `file.importAudio` / `file.exportAudio` 的系统文件对话框过滤器、用户取消语义、路径转换、异步读写编排和 HostBridge 响应统一收口在 `apps/desktop-shell/src-tauri/src/host_bridge/files.rs`;MIME、大小、base64、文件名清洗、本地副本读写和 HostBridge payload 组装统一收口在 `apps/desktop-shell/src-tauri/src/host_bridge/file_payloads.rs``dispatch.rs` 只负责按 method 委托 `export_desktop_host_bridge_*_file(...)` / `import_desktop_host_bridge_*_file(...)`。桌面壳配置检查会拒绝分发层直接调用 `.dialog()``blocking_save_file` / `blocking_pick_file`、文件 payload helper 或落盘 helper,避免文件访问边界重新散落。
- 2026-06-20 移动壳文件桥接载荷边界:Expo `file.exportText` / `file.importText` / `file.importDocument` / `file.exportImage` / `file.importImage` / `file.captureImage` / `file.importAudio` / `file.exportAudio` 的 DocumentPicker、ImagePicker、File、Sharing 系统交互、用户取消语义、缓存读写编排和 HostBridge 响应包装统一收口在 `apps/mobile-shell/src/host-bridge/files.ts`;MIME、大小、base64、文件名清洗、图片 / 音频 bytes 匹配和 picker 结果到 HostBridge payload 的组装统一收口在 `apps/mobile-shell/src/host-bridge/filePayloads.ts`。移动壳单端配置检查和根级 `npm run check:native-shells` 会把 `filePayloads.ts` 纳入结构清单与 HostBridge 源码扫描,避免文件载荷边界重新散落到分发层或 shell 层。
- 2026-06-20 移动文件动作单测边界:`apps/mobile-shell/src/host-bridge/files.test.ts` 直接覆盖 Expo 文件动作 helper 的文本导出、系统分享不可用、文本 / 文档 / 音频导入、用户取消、图片相册导入、相机权限拒绝和音频二进制导出;单端配置检查会反查这些动作测试存在,根级 `npm run check:native-shells` 会把该测试文件列入移动桥接层结构清单,避免系统文件交互只靠完整 HostBridge bridge 流程间接覆盖。
- 2026-06-20 移动文件导出分享不可用边界:Expo `file.exportText` / `file.exportImage` / `file.exportAudio``Sharing.isAvailableAsync()` 返回 false 时必须直接返回 `unsupported_capability`,不得写入 Expo cache,也不得调用 `Sharing.shareAsync` 或伪造 saved 成功;`apps/mobile-shell/src/host-bridge/files.test.ts` 用三类导出参数化覆盖该顺序,配置检查反查“不写缓存”断言。
- 2026-06-20 移动文件载荷单测边界:`apps/mobile-shell/src/host-bridge/filePayloads.test.ts` 直接覆盖移动壳文件载荷 helper 的 base64、UTF-8 byte、MIME / 扩展名归一、图片 / 音频 bytes 匹配、导出文件名补扩展、导入大小门禁和 ImagePicker payload 转换;根级 `npm run check:native-shells` 会把该测试文件列入移动桥接层结构清单,防止后续只靠完整 HostBridge bridge 流程间接覆盖文件安全边界。
- 2026-06-20 移动本地通知单测边界:`apps/mobile-shell/src/host-bridge/notifications.test.ts` 直接覆盖 Expo `notification.showLocal` 的已授权 / iOS provisional 权限复用、alert-only 权限请求、权限拒绝失败、iOS 即时调度、Android 固定 channel、共享 payload 归一和结构化 `delivered_to_system` 成功响应;根级 `npm run check:native-shells` 会把该测试文件列入移动桥接层结构清单,避免移动通知边界只靠完整 HostBridge bridge 流程间接覆盖。
- 2026-06-20 桌面能力清单单测边界:Tauri `capabilities.rs` 必须用 Rust 单测同时覆盖桌面 runtime capability 清单顺序、无重复、真实桌面能力完整包含,并显式排除 `auth.requestLogin``payment.request``file.captureImage``scanner.scanQrCode``haptics.impact` 等未接入能力;桌面单端配置检查会反查该测试边界,避免只靠方案文档或共享 profile 发现桌面壳能力伪声明。