danswer(Onyx)Box 连接器每日集成测试环境搭建与运行指南

发布时间:2026/9/10 6:48:27
danswer(Onyx)Box 连接器每日集成测试环境搭建与运行指南 danswerOnyxBox 连接器每日集成测试环境搭建与运行指南【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer本文以仓库 backend/tests/daily/connectors/box/README.md 为核心系统讲解如何在真实 Box 企业环境中搭建一套可复现的测试语料库corpus使 test_box_basic.py 中的每日集成测试全部通过。读完本文你将掌握 Box 开发者账号申请、CCGClient Credentials Grant应用配置、测试用户与协作矩阵搭建、密钥注入方式以及从测试断言反推 BoxConnector 文档索引与权限同步原理的完整链路。一、背景为什么需要一套真实的 Box 测试企业danswer现品牌为 Onyx通过连接器把第三方数据源接入统一检索。Box 连接器的实现位于 backend/onyx/connectors/box/它依赖 Box 的 CCG 认证、用户模拟impersonation、协作/共享链接权限解析等一系列需要真实企业租户才能触发的 API 行为因此仓库中除了可离线运行的单元测试外还专门保留了backend/tests/daily/connectors/box/目录下的每日测试daily tests它们直接对着真实 Box 企业发起请求。README.md开篇就强调了两类测试的分工每日测试test_box_basic.py需要一套按文档精确搭建的测试企业测试会逐字符断言语料库中的文件名与文件内容names and file contents must match character-for-character任何偏差都会导致断言失败。单元测试位于backend/tests/unit/onyx/connectors/box/不需要任何上述环境完全离线运行。这套语料库并非随意造几个文件而是刻意覆盖了多种共享级别文件夹级 Viewer、文件级 Editor、文件夹级 Uploader、开放共享链接、完全无共享用于验证连接器的权限同步permission sync逻辑——这正是文档强调语料即断言、断言即语料的原因。二、前置条件Box 开发者账号与普通账号的区别文档第 1 步指出搭建测试企业的前提是拥有一个Box 开发者账号而不是普通用户账号通过 https://developer.box.com 免费注册即可获得一个sandbox 企业sandbox enterprise你同时是管理员拥有 Admin Console 与 Developer Console 的访问权限。普通的 box.comIndividual/Free 账号不是开发者账号也无法升级转换——它背后没有企业enterprise因此App Enterprise Access、CCG、Admin Console、托管用户managed users、群组等能力全部不可用Developer Console 会报 some of your settings could not be saved。三种可行的注册路径用全新邮箱走开发者注册流程、注册 Box Business 试用版、或使用由付费 Box 企业签发的开发者沙箱。这一前置差异直接决定了后续步骤能否进行是最常见的卡在第一步的原因。三、创建 CCG Platform App3.1 创建应用进入 Developer Console创建Platform App → Custom App。认证方式选择Server Authentication (Client Credentials Grant)——即 CCG这是连接器底层 BoxCCGAuth / CCGConfig 使用的服务端认证方式无需用户交互式授权。在应用的Configuration标签页完成三组关键设置配置项取值作用结合源码说明App Access LevelApp Enterprise Access使应用能以企业身份访问整个企业的内容是 CCG 与用户模拟的前提Application ScopesRead all files and folders stored in Box读取文件/文件夹内容与元数据索引必需Application ScopesManage users群组同步需要枚举企业用户也是按邮箱解析用户 ID 实现模拟的必要权限见下方 3.3Application ScopesManage groups权限同步需要枚举群组及成员关系Advanced FeaturesGenerate user access tokens连接器通过box_user_email模拟impersonate指定用户语料就存放在该用户的 All Files 中保存后在Authorization标签页点击Review and Submit提交审核。到Admin Console → Apps → Custom Apps Manager中批准待处理的应用授权。每次修改 scope 后都必须重新批准——scope 的变更在重新授权前不会生效这是排障时极易忽略的点。3.2 收集凭据从 Configuration 标签页收集三样信息Client ID应用的公开标识。Client Secret注意Fetch Secret按钮要求 Box 账号先开启双重认证2FA否则会静默失效底层请求返回two_fa_enrollment_required。需先在账号 Settings 中启用 2FA再回来获取。Enterprise ID也在应用的 General Settings 标签页可见。这三项与box_user_email一起构成连接器load_credentials所需的四类凭据connector.py 定义了box_client_id、box_client_secret、box_enterprise_id、box_user_email四个键名。3.3 凭据在源码中的落地方式从源码看BoxConnector.load_credentialsconnector.py会校验 client id / secret / enterprise id 三项必填box_user_email可选。构建认证对象后enterprise_client以企业服务账号身份访问用于群组/用户枚举等管理级 APIcontent_client读取内容时使用——若配置了box_user_email会先通过_resolve_user_id_from_emailconnector.py借助Manage users scope将邮箱解析为数字用户 ID再以auth.with_user_subject(user_id)模拟该用户读取其 All Files未配置时退化为服务账号。这也解释了为什么 README 要求开启Manage usersscope模拟用户依赖它若未开启源码会抛出InsufficientPermissionsError并提示补上该 scope 后重新授权。四、创建测试用户文档第 3 步定义了两种用户角色主用户primary user就是你自己的管理员账号。它的登录邮箱即BOX_USER_EMAIL——连接器会模拟这个用户因此测试语料库必须存放在该用户的 All Files下。协作用户collaborator通过POST /users提供loginname或 Admin Console → Users Groups → Add User 创建的第二个托管用户。它只需存在、无需登录其登录邮箱即BOX_COLLABORATOR_EMAIL用于验证权限同步矩阵。一个细节Box 会拒绝向已停用deactivated用户发起协作错误为cannot_invite_deactivated_user。若你想要的邮箱已被某个停用账号占用改用同一收件箱的alias形式即可例如oauthboxonyx.app。五、搭建测试语料库5.1 目录结构必须逐字符一致在主用户的 All Files 中按如下结构创建文件与文件夹文件名、文件内容必须与文档/测试中的常量完全一致test_box_basic.py 中定义了全部内容的字面量Onyx Connector Test Folder/ ├── root_doc.txt content: box root doc for onyx connector tests ├── public_doc.txt content: public doc for onyx connector tests ├── editor_doc.txt content: editor doc for onyx connector tests ├── Onyx Example Link web link (bookmark) - https://www.onyx.app │ description: example bookmark for onyx connector tests ├── Subfolder A/ │ └── alpha.txt content: alpha doc for onyx connector tests ├── Shared Folder/ │ └── shared.txt content: shared doc for onyx connector tests └── Uploader Folder/ └── uploader_doc.txt content: uploader doc for onyx connector tests对应到测试期望6 个文档EXPECTED_DOC_NAMES与 4 个文件夹层级节点EXPECTED_FOLDER_NAMES含根测试文件夹。5.2 共享矩阵语料即权限断言这套语料的关键在于为协作用户构造多个共享级别这正是权限同步断言的核心test_perm_sync_external_access条目协作/链接方式协作方可读Shared Folder文件夹级Viewer是→shared.txteditor_doc.txt文件级Editor是Uploader Folder文件夹级Uploader否仅上传public_doc.txt开放共享链接公开public其余所有条目无仅所有者owner-only几个必须注意的细节必须上传真实.txt文件本地写好再拖拽上传。Box Notes 是另一种文件类型无法抽取为期望文本。文件末尾允许有一个换行符测试会去除。Uploader 是刻意构造的负例uploader是 Box 仅上传upload-only角色连接器不得为其授予读权限。uploader_doc.txt仍会被索引所有者可读但协作用户必须不在该文档的访问集合中test_box_basic.py。同一企业内的托管用户邀请会自动接受auto-accept需逐个确认协作状态是active而非 pending。public_doc.txt的共享链接访问级别选People with the link即open级别不设密码。不要给Onyx Connector Test Folder本身、Subfolder A、root_doc.txt、alpha.txt添加任何共享链接或协作——测试断言它们为仅所有者可见。Onyx Example Link是一个web link书签而非文件在根测试文件夹中创建指向https://www.onyx.app并填写上述描述。它仅在连接器开启include_web_links时被索引产出一个薄书签文档名称 描述作为文本不会抓取链接指向的页面内容。5.3 群组再创建一个名称完全等于Onyx Test Group的群组并把协作用户加为成员。不要把这个群组协作到任何文件夹上——它存在的唯一目的是验证群组同步group sync。5.4 快速搭建建议文档给出的最快捷方式是使用 Box API Developer TokenDeveloper Console → 你的应用 →Developer TokenPOST /folders建目录POST /files/content上传主机传文件POST /web_links建书签POST /collaborations每种共享级别各一次PUT /files/:id附带shared_link.accessopen开放共享链接POST /groupsPOST /group_memberships建群与加成员六、密钥注入方式6.1 解析顺序与命名测试密钥按以下顺序解析进程环境变量 → 仓库.vscode/.env→ AWS Secrets ManagerCI 使用。该逻辑实现在 backend/tests/utils/aws_secrets.py其中_get_local_secrets明确先读os.environ、再读.vscode/.env_get_aws_secrets则按前缀批量拉取 Secrets Manager。名称对照如下本地环境变量AWS Secrets Manager 键CI值BOX_CLIENT_IDtest/box-client-id应用 Client IDBOX_CLIENT_SECRETtest/box-client-secret应用 Client SecretBOX_ENTERPRISE_IDtest/box-enterprise-idEnterprise IDBOX_USER_EMAILtest/box-user-email主管理员用户邮箱BOX_COLLABORATOR_EMAILtest/box-collaborator-email协作用户邮箱五个密钥名在 backend/tests/utils/secret_names.py 的TestSecret枚举中定义如BOX_CLIENT_ID box-client-id测试通过pytest.mark.secrets(...)声明所需密钥test_box_basic.py不满足时会自动跳过。6.2 写入 AWS Secrets ManagerCI 场景下在 us-east-2 区域创建test/前缀下的五个密钥例如aws secretsmanager create-secret --region us-east-2 \ --name test/box-client-id --secret-string client id七、运行测试7.1 每日测试命令source .venv/bin/activate export BOX_CLIENT_ID... BOX_CLIENT_SECRET... BOX_ENTERPRISE_ID... \ BOX_USER_EMAIL... BOX_COLLABORATOR_EMAIL... pytest -xv backend/tests/daily/connectors/box7.2 连接器开发入口点不想走 pytest、只想手动探查时连接器自带 dev 入口connector.py脚本读取上述环境变量通过ConnectorRunner从 1970 年至今遍历并打印文档与文件夹描述。可用BOX_FOLDER_IDSid限定遍历范围多个 id 用逗号分隔否则默认从根文件夹0开始PYTHONPATHbackend python backend/onyx/connectors/box/connector.py八、测试断言详解六个用例逐个拆解test_box_basic.py 中的断言与 README 语料一一对应是理解连接器行为的活的说明书test_load_documents遍历连接器全部文档断言——文档集合恰好等于 6 个期望文档层级节点集合等于 4 个文件夹每个文档的抽取文本与预期内容逐字符一致metadata[path]正确反映目录层级如alpha.txt的 path 为Onyx Connector Test Folder/Subfolder A文档 id 以box-file-开头时间戳存在且为 UTCtzinfo timezone.utc主所有者邮箱等于被模拟用户get_user_me().login首节链接以https://app.box.com/file/开头对应 box_file_link 的实现。test_web_links开启include_web_linksTrue后书签被索引为 id 以box-weblink-开头的文档其 section 链接指向目标 URLhttps://www.onyx.app文本中携带名称 描述对应 _convert_web_link 的f{name}\n{description}拼接逻辑。test_poll_window_filters_documents_but_not_hierarchy把轮询窗口设为 1970 年时间戳 1_000_000 秒内不含任何真实文件断言文档为空、但文件夹层级树仍然完整输出——因为文件夹节点不依赖修改时间验证了 BFS 遍历与时间窗口过滤的分离设计。test_perm_sync_external_access需要 EE 模块enable_eefixture在include_permissionsTrue下逐项验证共享矩阵——shared.txt文件夹 Viewer与editor_doc.txt文件 Editor把协作用户列入external_user_emails且is_publicFalseuploader_doc.txt文件夹 Uploader不包含协作用户但所有者仍在root_doc.txt仅所有者public_doc.txt的is_publicTrue。同时断言Shared Folder这个层级节点自身也携带该访问集合。注意测试默认对连接器关闭include_web_links因此该用例中文档集合仍精确等于 6 个。test_group_sync调用box_group_syncbackend/ee/onyx/external_permissions/box/group_sync.py断言两个层面的群一是真实群组Onyx Test Group以box-group-id为 id 同步且包含协作用户二是合成群box-enterprise-all-users-enterprise_idbox_all_enterprise_users_group_id包含企业内每一个托管用户——它支撑的是企业内公司范围共享链接的权限语义。该实现还包含一个值得注意的防御逻辑Box 群成员端点仅支持 offset 分页且上限约 1 万超限时抛BoxGroupTooLargeError并跳过该群而不是用不完整的成员集替换旧成员避免误撤销权限。test_validate_connector_settings合法凭据 真实文件夹 id 应通过validate_connector_settings()与probe_group_listing_permission()后者探测Manage groups/Manage usersscope缺少时抛InsufficientPermissionsError见 connector.py而指向不存在的文件夹 id如999999999999999必须抛出ConnectorValidationError——对应 validate_connector_settings 中 403/404 的分支处理。九、连接器实现要点源码级佐证遍历模型连接器采用带检查点checkpoint的 BFS 爬取。BoxConnectorCheckpointmodels.py持有待处理文件夹队列todo、当前分页文件夹current与 Box 不透明 markercurrent_marker、以及已访问文件夹集合seen_folder_ids用于去重——同时配置某文件夹及其祖先作为入口时避免重复索引。每次_load_one_page只推进一个单位播种入口、开始下一文件夹或翻一页单页_BOX_PAGE_SIZE 200。时间窗口_in_time_window按modified_at过滤文件与 web link无修改时间的条目保守视为在窗口内避免误删。大小与类型门槛BOX_CONNECTOR_SIZE_THRESHOLD默认 20 MB见 app_configs.py超限文件在下载/索引时被跳过不支持的文件扩展名直接跳过。文档 id 约定文件为box-file-file_id、web link 为box-weblink-web_link_id、群组为box-group-group_id、企业全员合成群为box-enterprise-all-users-enterprise_id按企业 id 隔离避免同一租户下两个 Box 连接器因共享群 id 造成公司链接文档串权。normalize_box_login会把登录邮箱小写化保证与 Onyx 内部统一小写的用户身份在访问过滤时精确匹配。权限解析的版本化设计access.py中的resolve_box_*_access均通过fetch_versioned_implementation_with_fallback动态加载onyx.external_permissions.box.access的实现开源默认走 noopEE 版本backend/ee/onyx/external_permissions/box/access.py提供真正的协作/共享链接解析。十、常见问题速查现象可能原因与处理Developer Console 报 some of your settings could not be saved用的是个人免费账号而非开发者/企业账号需重新走开发者注册Fetch Secret 按钮无反应账号未开启 2FA先到账号 Settings 启用再回来获取改了 scope 后行为未变scope 变更需在 Admin Console 重新批准应用授权邀请协作报cannot_invite_deactivated_user目标邮箱被停用账号占用改用alias邮箱索引结果缺少文档或文本不符文件名/内容必须与测试常量逐字符一致Box Notes 不被识别为文本文件需真实.txt上传权限断言中协作用户出现在不应出现的位置检查是否误给根测试文件夹/Subfolder A/root_doc.txt/alpha.txt添加了共享Uploader 角色为仅上传连接器必须不授读权限验证报 401/404凭据无效或被模拟用户不存在见 validate_connector_settings 的区分逻辑验证报 403缺少所需 scope读内容 /Manage users/Manage groups开启后重新授权结语Box 连接器的每日测试是一套用真实语料说话的集成验证目录结构与共享矩阵既是测试输入也是权限同步契约。按本文流程完成开发者账号、CCG 应用、双用户、六文件四文件夹一链接一群组的搭建后即可在本地或 CIAWS Secrets Manager中稳定运行 test_box_basic.py并为深入阅读 BoxConnector 的 BFS 遍历、检查点恢复、权限解析与群组同步实现提供可对照的活样本。【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考