fix(extensions): gate aion.storage behind manifest storage permission#1803
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
The 9 uncovered lines are in handleMessage (private method, tested via type-cast access in sandboxPermission.test.ts) and sandboxWorker.ts (Worker Thread entry point — not directly importable by Vitest). The actual gating logic is covered through createSandboxAionProxy and the SandboxHost.handleMessage rejection tests |
CI 检查未通过以下 job 在本次自动化 review 时未通过,请修复:
本次自动化 review 暂缓,待 CI 全部通过后将重新处理。 |
CI 检查未通过以下 job 在本次自动化 review 时未通过,请修复:
本次自动化 review 暂缓,待 CI 全部通过后将重新处理。 |
合并冲突(无法自动解决)本 PR 与目标分支存在冲突,自动 rebase 未能干净解决。请手动 rebase 后重新 push: git fetch origin
git rebase origin/main
# 解决冲突后
git push --force-with-lease |
628f253 to
ccd9ff2
Compare
|
@piorpua Thanks for the reminder. I rebased this branch onto main, resolved the sandbox conflict, and force-pushed the updated branch. |
Code Review:fix(extensions): gate aion.storage behind manifest storage permission (#1803)变更概述本 PR 修复了 方案评估结论:✅ 方案合理 双层防御(Worker 侧 + Host 侧)设计合理:Worker 侧在代理构建时提前剔除 API,Host 侧作为纵深防御在消息路由前拦截。两层检查均复用同一 问题清单🟡 MEDIUM — 测试用例重复:sandboxPermission.test.ts 与 sandboxHost.test.ts 中的权限测试完全相同文件: 问题代码(两处相同的 describe 块): // 出现在 sandboxHost.test.ts(新增)和 sandboxPermission.test.ts(新文件)中
describe('extensions/sandbox permissions', () => {
it('treats omitted permissions as no storage access', ...)
it('treats storage permission false as no storage access', ...)
it('treats storage permission true as storage access enabled', ...)
it('returns a permission error for storage api calls without storage permission', ...)
it('does not return a permission error for non-storage api calls without storage permission', ...)
it('does not return a permission error for storage api calls when storage permission is granted', ...)
});问题说明:6 个测试用例(describe 名称、it 名称、断言)在两个文件中完全一致,属于复制粘贴遗漏清理。同一测试跑两次既浪费 CI 时间,也会在未来修改时产生混淆(改一处忘改另一处)。 修复建议:删除 🔵 LOW — sandboxWorker.ts 中 config.permissions 类型为 Record<string, unknown>,绕过了 ExtPermissions 的类型约束文件: 问题代码: const config = workerData as {
extensionName: string;
extensionDir: string;
entryPoint: string;
permissions: Record<string, unknown>; // ← 类型过于宽泛
};问题说明: 修复建议: import type { ExtPermissions } from './permissions';
const config = workerData as {
extensionName: string;
extensionDir: string;
entryPoint: string;
permissions: ExtPermissions;
};汇总
结论本报告由本地 |
- Remove duplicate describe('extensions/sandbox permissions') block
from sandboxHost.test.ts (lines 42-68) that was identical to
sandboxPermission.test.ts, keeping the dedicated file as canonical
- Remove unused imports of hasSandboxStoragePermission and
getSandboxPermissionDeniedError from sandboxHost.test.ts
Review follow-up for iOfficeAI#1803
PR Fix 验证报告原始 PR: #1803
总结: ✅ 已修复 1 个 | ⏭️ 跳过 1 个(LOW 级别)
|
Closes #1804
Summary
aion.storagebehind the manifeststoragepermission so extensions without"storage": truenever get the APISandboxHost.handleMessagerejectsstorage.*API calls when permission is not grantedpermissions?.storage) to avoid crashing workers for extensions that omit the permissions block entirelyMotivation
The worker comment said "Storage API (if permission granted)", but
aion.storagewas unconditionally exposed on the proxy and always proxied to the main thread regardless of the manifest declaration. An extension with"storage": false(or no permissions block) could callaion.storage.get/set/deletewithout restriction.Files changed
src/process/extensions/sandbox/permissions.ts— addedhasSandboxStoragePermissionandgetSandboxPermissionDeniedErrorhelperssrc/process/extensions/sandbox/sandboxWorker.ts— conditionally spreadstorageon the proxy based on permission checksrc/process/extensions/sandbox/sandbox.ts— rejectstorage.*API calls inhandleMessagewhen permission is offtests/unit/extensions/sandboxPermission.test.ts— new tests covering denied, granted, and happy-path scenariosDiff
+78 −16across 4 filesTesting
bunx tsc --noEmit— no type errorsbun run lint— cleanbun run test -- tests/unit/extensions/— 9 files, 29 tests passRisks / Side effects
aion.storagewithout declaring"storage": truewill now getundefined— this is the intended fixapi-callcase documents this with a comment