feat: support secure XFT submission attachments
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
This commit is contained in:
@@ -34,7 +34,9 @@ Agent 面向统一审批语义,不直接理解钉钉 `processInstanceId/taskId
|
||||
|
||||
草稿不是网关工具或上游单据状态,而是 Agent 的本地文件工作流。只有用户明确要求起草或保存时,Agent 才在当前 OS 用户的私有应用数据目录写入草稿;Windows 使用 `%LOCALAPPDATA%\DingTalkApproval\drafts`,macOS 使用 `~/Library/Application Support/DingTalkApproval/drafts`,Linux 使用 `${XDG_DATA_HOME:-~/.local/share}/dingtalk-approval/drafts`。POSIX 目录/文件权限分别为 `0700`/`0600`,保存采用同目录临时文件原子替换。宿主没有本地文件能力时明确不支持持久草稿,禁止退化为网关存储。
|
||||
|
||||
草稿仅保存用户填写值、来源和模板显示名、可选项决定,以及附件本地路径、大小、修改时间和 SHA-256。它不保存 Token、当前用户身份、短期 `templateId`/`confirmationId`/`revokeId`、审批动作引用或完整上游 Schema,也不复制或预上传附件。恢复时按来源和模板名重新实时列模板并获取 Schema;模板不唯一、字段变化、附件丢失或哈希变化都必须回到用户确认。当前 MCP 没有附件上传工具,本机路径或文件内容不能作为上游附件编号提交;实时 Schema 要求附件编号时只能保留草稿并转到原生客户端。普通草稿超过 90 天未更新会在下次草稿操作时清理。
|
||||
草稿仅保存用户填写值、来源和模板显示名、可选项决定,以及附件所属表单字段、本地路径、大小、修改时间和 SHA-256。它不保存 Token、当前用户身份、短期 `templateId`/`confirmationId`/`revokeId`、审批动作引用、薪福通附件编号或完整上游 Schema,也不复制或预上传附件。恢复时按来源和模板名重新实时列模板并获取 Schema;模板不唯一、字段变化、附件丢失或哈希变化都必须回到用户确认。普通草稿超过 90 天未更新会在下次草稿操作时清理。
|
||||
|
||||
附件准备阶段由签名本地 Bridge 打开用户明确选择的普通文件,拒绝符号链接、读取中变化的文件、伪造扩展名、零字节以及超限内容;支持 PDF、OFD、JPG、PNG、XML 和 ZIP,最多 10 个,单文件及总量均不超过 50MB。Bridge 重新计算 SHA-256,只把字段名称、文件名、大小和哈希发送给 `approval_prepare_submission`,因此预览无上传副作用且不含本地路径。`confirmationId` 绑定这份附件清单;用户最终确认后 Bridge 才把原始字节通过 OAuth 保护的专用 HTTPS 路由发送给网关。Nginx 关闭请求缓冲,网关只在内存中实时转发到薪福通自定义附件上传接口,不写数据库或磁盘。上传返回的薪福通 `fileId` 被封装为用户、本次确认和附件元数据绑定的 15 分钟加密引用;创建单据时才转换成实时 `ACCESSORIES` 字段的 JSON 附件编号数组,Agent 和用户都看不到上游编号。
|
||||
|
||||
正式提交仍完整经过网关的身份、模板、字段、发票查重、预览和一次性确认校验。本机文件被修改不能扩大权限。提交成功或即时完成后删除草稿;确定失败时保留并回到编辑;`outcome_uncertain` 时冻结草稿、丢弃短期引用并禁止自动重试,直到本人发起历史或原生客户端证明结果。
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
- 兼容安装结果的 `loginCommand` 能在 MCP 未加载时刷新登录链接;MCP 已加载时 `approval_login` 完成同一操作。不得因链接过期而重装,首次成功响应只展示一次 onboarding 示例。
|
||||
- 只读验证待办、本人已处理历史、本人发起历史、历史默认最近 30 天及显式时间窗口、搜索、详情、费用结构化字段、动作、模板 Schema、部门/城市选项和越权拒绝;历史引用必须被动作查询和批处理拒绝。
|
||||
- 发票查重验证钉钉/XFT 跨来源精确匹配、弱匹配、用户隔离、状态更新、来源不可用、历史截断、详情失败、并发确认、35 天过期清理和网关重启恢复;数据库不得出现用户 ID、发票原号、审批正文或附件。重复风险和不完整覆盖未获用户确认时不得签发可提交 `confirmationId`。
|
||||
- 本机草稿验证 Windows/macOS/Linux 私有目录选择、POSIX `0700`/`0600`、原子保存、90 天普通草稿清理、模板和 Schema 实时恢复、附件 SHA-256 变化、提交成功删除、确定失败保留及 `outcome_uncertain` 冻结。确认网关数据库、日志、发行包和项目仓库都不出现草稿正文,草稿中不保存 Token、身份 ID、短期模板/确认/撤回引用或完整 Schema。
|
||||
- 本机草稿验证 Windows/macOS/Linux 私有目录选择、POSIX `0700`/`0600`、原子保存、90 天普通草稿清理、模板和 Schema 实时恢复、附件 SHA-256 变化、提交成功删除、确定失败保留及 `outcome_uncertain` 冻结。附件另验证符号链接/读取中变化/伪造类型/大小与数量上限在零上传前拒绝,prepare 不上传且不向网关发送路径,submit 只在最终确认后上传,multipart 签名不含 `x-alb-digest`,上游 `fileId` 只进入创建请求的实时附件字段。确认 Nginx 请求缓冲关闭,网关数据库、磁盘、日志、发行包和项目仓库都不出现附件字节、草稿正文或本地路径;草稿中不保存 Token、身份 ID、短期模板/确认/撤回引用、上游附件编号或完整 Schema。
|
||||
- 真实写操作只执行用户明确授权的样本;任何 `outcome_uncertain` 都停止,不自动重试。
|
||||
- Mock 契约确认网关和 bridge 的批量 Schema 均固定为 20;第 6 个截断引用及任一无效退回目标都会返回 `preflight_failed`、`writesStarted=false`,上游写调用数为 0。
|
||||
- 代表性 v4 引用长度满足钉钉 OA 不超过 128 字符、薪福通不超过 80 字符,并通过篡改、过期、跨用户、跨密钥、同密钥重启及 v2/v3 兼容测试。
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
| 钉钉 OA | 差旅费用报销_捷康 | 仅客户端 | 钉钉费控报销套件含行程、报销明细、发票、收款账户和企业主体;另有关联出差申请和项目字段 |
|
||||
| 钉钉 OA | 业务招待费用报销_捷康 | 仅客户端 | 钉钉费控报销套件含报销明细、发票、收款账户和付款主体 |
|
||||
|
||||
薪福通自定义字段在工具内部统一使用 `customFieldValues[].fieldNumber/fieldValue`,但用户不应看到或提供这些引用。日期字段使用 `yyyy-MM-dd HH:mm`;部门由可读名称选择后内部映射;下拉框与表格子字段使用实时名称映射。人员、附件及其他没有安全名称查询或上传能力的字段标记为 `client_only`,不会要求用户填写花名册编号或附件编号。`approval_get_submission_schema` 会返回实时 `valueFormat`、`selectionCapability` 和该模板的精简 `minimalExample`;后者只说明 `values` 形状,所有尖括号占位符都必须由用户业务回答或实时选项替换,不能原样提交。Agent 不得按字段名称猜编码或结构。
|
||||
薪福通自定义字段在工具内部统一使用 `customFieldValues[].fieldNumber/fieldValue`,但用户不应看到或提供这些引用。日期字段使用 `yyyy-MM-dd HH:mm`;部门由可读名称选择后内部映射;下拉框与表格子字段使用实时名称映射。人员及其他没有安全名称查询能力的字段标记为 `client_only`,不会要求用户填写花名册编号。附件字段返回 `attachmentCapability.status=supported`:Agent 只把本机草稿中的字段名称和文件引用传给签名 Bridge;prepare 阶段复核文件并只发送不含路径的元数据,最终确认后的 submit 才上传。薪福通附件编号由网关封装并直接写入 `ACCESSORIES` 字段,不能由 Agent 传入 `values.customFieldValues`。`approval_get_submission_schema` 会返回实时 `valueFormat`、`selectionCapability`、`attachmentCapability` 和该模板的精简 `minimalExample`;后者只说明 `values` 形状,所有尖括号占位符都必须由用户业务回答或实时选项替换,不能原样提交。Agent 不得按字段名称猜编码或结构。
|
||||
|
||||
薪福通模板要求承担部门、城市或费用类型时,使用同一 `templateId` 调用 `approval_get_submission_options`。`kind=department` 只会返回当前登录用户本人档案中的可选组织;`kind=city` 可用 `query` 按城市名称搜索;`kind=expense_type` 先读取模板内嵌选项,再按需读取企业多级费用类型数据源。多级数据源分页接口按正式契约把 `start/limit` 放在 query,并用列表的 `seqId` 读取详情中的 `optionSaveDtoList`;该接口只覆盖企业自定义多级数据源,薪福通正式 OpenAPI 当前没有独立的费用类型目录查询。模板没有内嵌选项且企业多级数据源为空或不含费用类型时,工具会明确返回这两项实时检查结果并引导在费用管理页面确认或使用客户端,不再包装成笼统的获取失败。费用申请、差旅预计费用及报销明细均标记对应选项源。固定枚举提供 `enumLabels`,例如出行方式、单程/往返、上午/下午、人民币和酒店星级;动态 `SELECT` 的 `options` 统一为 `{label, code}`,表格列也递归标准化。Agent 只向用户显示名称并在内部使用正式值,不得向用户索取内部编码。`approval_prepare_submission` 会对标准字段、自定义下拉和表格列做第二次反向解析,确认预览只保留业务名称;无法映射时不签发确认引用。城市全量接口较慢,网关给予独立的 45 秒超时并在进程内缓存字典 24 小时,不写入磁盘;费用类型保持实时且不落盘。响应不会暴露员工号、完整数据源或原始成员档案。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user