diff --git a/Makefile b/Makefile index 7bc1c702..ece3966c 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ APP_DART_DEFINE_BUILD ?= --dart-define=XWORKMATE_BUILD_NUMBER=$(APP_BUILD_NUMBER APP_DART_DEFINE_BUILD_DATE ?= --dart-define=XWORKMATE_BUILD_DATE=$(APP_BUILD_DATE) APP_DART_DEFINE_BUILD_COMMIT ?= --dart-define=XWORKMATE_BUILD_COMMIT=$(APP_BUILD_COMMIT) -.PHONY: help deps analyze test test-all test-flutter test-golden test-integration test-integration-macos test-patrol test-go test-ci check format run open-macos-xcode sync-version build-linux build-macos build-ios-sim package-deb package-rpm package-linux package-mac install-mac clean build-go-core render-release-docs docs-public-api check-export-compliance test-real-env-login-chain inspect-xworkmate-bridge-service test-api-contract test-api-scenario-contract check-api-external +.PHONY: help deps analyze test test-all test-flutter test-golden test-integration test-integration-macos test-patrol test-go test-ci check format run open-macos-xcode sync-version build-linux build-macos build-ios-sim ios-pods ios-pods-check build-ios-release-no-codesign verify-ios-release package-deb package-rpm package-linux package-mac install-mac clean build-go-core render-release-docs docs-public-api check-export-compliance test-real-env-login-chain inspect-xworkmate-bridge-service test-api-contract test-api-scenario-contract check-api-external help: ## Show available targets @grep -E '^[a-zA-Z0-9_.-]+:.*?## ' Makefile | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "%-18s %s\n", $$1, $$2}' @@ -108,6 +108,17 @@ build-ios-sim: ## Build the iOS app for the simulator $(FLUTTER) build ios --simulator $(APP_STORE_DART_DEFINE) --build-name=$(APP_VERSION) --build-number=$(APP_BUILD_NUMBER) $(APP_DART_DEFINE_VERSION) $(APP_DART_DEFINE_BUILD) $(APP_DART_DEFINE_BUILD_DATE) $(APP_DART_DEFINE_BUILD_COMMIT) bash scripts/check-apple-export-compliance.sh build/ios/iphonesimulator/Runner.app +ios-pods: ## Regenerate the iOS CocoaPods sandbox + cd ios && pod install + +ios-pods-check: ios-pods ## Verify Podfile.lock and Pods/Manifest.lock are in sync + cmp -s ios/Podfile.lock ios/Pods/Manifest.lock + +build-ios-release-no-codesign: ios-pods-check ## Build the iOS device app in release mode without codesigning + $(FLUTTER) build ios --release --no-codesign $(APP_STORE_DART_DEFINE) --build-name=$(APP_VERSION) --build-number=$(APP_BUILD_NUMBER) $(APP_DART_DEFINE_VERSION) $(APP_DART_DEFINE_BUILD) $(APP_DART_DEFINE_BUILD_DATE) $(APP_DART_DEFINE_BUILD_COMMIT) + +verify-ios-release: ios-pods-check build-ios-release-no-codesign analyze ## Regenerate pods, build iOS release without codesigning, and run static analysis + build-go-core: ## Build the external ACP bridge helper from xworkmate-bridge bash scripts/build-go-core.sh diff --git a/docs/cases/README.md b/docs/cases/README.md index 0ab6d1e9..073892d9 100644 --- a/docs/cases/README.md +++ b/docs/cases/README.md @@ -5,6 +5,7 @@ ## 当前入口 - [核心功能集成测试手动 Case](./core-integration-manual-cases.md) +- [AI 安全演进内容生成场景测试用例](./ai-security-evolution-content-scenario/README.md) ## 配套文档 diff --git a/docs/cases/ai-security-evolution-content-scenario/README.md b/docs/cases/ai-security-evolution-content-scenario/README.md new file mode 100644 index 00000000..787332ce --- /dev/null +++ b/docs/cases/ai-security-evolution-content-scenario/README.md @@ -0,0 +1,41 @@ +# AI 安全演进内容生成场景测试用例 + +这个目录保存一个用于 XWorkmate App 的内容生产场景测试用例。测试目标是验证 assistant 线程能围绕同一主题生成多平台文案与 PPT artifact,并保持产物归属当前线程 workspace。 + +## 场景主题 + +| 演进路径 | 当下判断 | +| --- | --- | +| 单机权限 | 权限不再只发生在单机,终端只是身份、数据和任务链路的入口。 | +| 网络边界 | 边界从机房防火墙变成 API、身份、设备、供应链和运行时的组合面。 | +| Web 安全 | Web 风险仍在,但主战场从页面漏洞扩展到业务流、插件、自动化调用和数据泄露。 | +| 云身份 | 云身份成为默认控制平面,权限漂移、密钥暴露和跨账号访问是主要风险。 | +| Zero Trust | Zero Trust 从口号进入执行层,核心是持续验证、最小权限和上下文决策。 | +| AI Agent 身份 | Agent 开始代表人执行任务,必须有独立身份、授权边界、审计链和可撤销能力。 | +| AI 模型与知识保护 | 模型、提示词、RAG 知识库、工具调用记录和业务语料共同成为新资产边界。 | + +## 产物 + +- [X 风格文案](./x-copy.md) +- [XHS 风格文案](./xhs-copy.md) +- [微信文章文案](./wechat-article.md) +- [PPT 演示稿](./ai-security-evolution-scenario.pptx) + +## App 手动测试提示词 + +```text +使用表格展示“单机权限 -> 网络边界 -> Web安全 -> 云身份 -> Zero Trust -> AI Agent 身份 -> AI模型与知识保护”的安全演进,右侧写“当下判断”。请基于这张表同时输出: +1. X 风格文案,Markdown 文件 +2. XHS 风格文案,Markdown 文件 +3. 微信文章文案,Markdown 文件 +4. PPT 文件 + +要求:四个产物都写入当前线程 workspace,返回文件路径,并说明每个产物适合的发布场景。 +``` + +## 期望结果 + +- 当前线程 artifact 区出现 3 个 `.md` 文件和 1 个 `.pptx` 文件。 +- 三份 Markdown 使用同一张演进对照表,但语气、结构和长度不同。 +- PPT 至少包含封面、演进总览、当下判断、Agent 身份、模型与知识保护、行动清单。 +- 同线程继续追问修改任一平台文案时,仍基于这四个产物上下文。 diff --git a/docs/cases/ai-security-evolution-content-scenario/ai-security-evolution-scenario.pptx b/docs/cases/ai-security-evolution-content-scenario/ai-security-evolution-scenario.pptx new file mode 100644 index 00000000..17804a52 Binary files /dev/null and b/docs/cases/ai-security-evolution-content-scenario/ai-security-evolution-scenario.pptx differ diff --git a/docs/cases/ai-security-evolution-content-scenario/wechat-article.md b/docs/cases/ai-security-evolution-content-scenario/wechat-article.md new file mode 100644 index 00000000..2d90126f --- /dev/null +++ b/docs/cases/ai-security-evolution-content-scenario/wechat-article.md @@ -0,0 +1,123 @@ +# 从单机权限到 AI 模型与知识保护:安全边界正在重新定义 + +## 开场 + +过去几十年,企业安全一直围绕“边界”展开。 + +早期的边界是单机权限:谁能登录这台机器,谁能读取这个目录,谁能执行这个程序。 + +后来边界变成网络:哪些端口开放,哪些网段能访问,哪些请求可以穿过防火墙。 + +再后来,业务搬到 Web 和云上,安全控制面继续向应用、身份、API、云账号和运行时迁移。 + +到了 AI Agent 时代,边界又一次发生变化:系统里开始出现一个会代表人执行任务的新主体。 + +这意味着,安全不再只是保护“入口”,而是要治理“行动”。 + +## 一张表看安全边界的演进 + +| 演进路径 | 当下判断 | +| --- | --- | +| 单机权限 | 权限不再只发生在单机,终端只是身份、数据和任务链路的入口。 | +| 网络边界 | 边界从机房防火墙变成 API、身份、设备、供应链和运行时的组合面。 | +| Web 安全 | Web 风险仍在,但主战场从页面漏洞扩展到业务流、插件、自动化调用和数据泄露。 | +| 云身份 | 云身份成为默认控制平面,权限漂移、密钥暴露和跨账号访问是主要风险。 | +| Zero Trust | Zero Trust 从口号进入执行层,核心是持续验证、最小权限和上下文决策。 | +| AI Agent 身份 | Agent 开始代表人执行任务,必须有独立身份、授权边界、审计链和可撤销能力。 | +| AI 模型与知识保护 | 模型、提示词、RAG 知识库、工具调用记录和业务语料共同成为新资产边界。 | + +## 第一阶段:单机权限 + +单机时代,安全问题相对直接。 + +系统管理员关心的是本机账号、文件权限、进程权限和本地审计。权限模型围绕一台机器展开,攻击面也主要集中在本机登录、提权和文件访问。 + +这个阶段的核心问题是:谁能进入这台机器? + +## 第二阶段:网络边界 + +当系统开始联网,边界从单机扩展到网络。 + +防火墙、网段隔离、端口策略、VPN 和入侵检测成为安全体系的关键组件。企业开始把“内网”看作可信区域,把“外网”看作不可信区域。 + +这个阶段的核心问题是:哪些连接可以进入系统? + +## 第三阶段:Web 安全 + +业务上 Web 之后,安全风险进入应用层。 + +SQL 注入、XSS、CSRF、越权访问、上传漏洞、会话劫持等问题,使安全团队必须理解业务逻辑本身。攻击者不一定需要突破网络边界,只要利用应用逻辑缺陷,就可能拿到数据或权限。 + +这个阶段的核心问题是:业务入口是否可信? + +## 第四阶段:云身份 + +云计算普及后,身份成为新的控制平面。 + +云账号、角色、策略、密钥、服务账号、跨账号授权,共同决定资源能否被访问。很多严重事故并不是因为服务器被攻破,而是因为身份权限过大、密钥泄露、临时授权失控。 + +这个阶段的核心问题是:谁以什么身份访问什么资源? + +## 第五阶段:Zero Trust + +Zero Trust 的价值,是把“默认信任”从架构里拿掉。 + +不再因为请求来自内网、某台设备或某个固定网段就直接放行,而是持续验证身份、设备、位置、行为、风险和上下文,并以最小权限完成授权。 + +这个阶段的核心问题是:这一次访问,在当前上下文里是否仍然可信? + +## 第六阶段:AI Agent 身份 + +AI Agent 出现后,安全主体发生变化。 + +传统应用多数是被动响应请求,而 Agent 会主动规划任务、调用工具、读写文件、访问外部系统,甚至连续执行多步操作。 + +因此,Agent 不能只是“某个用户会话里的模型”。它需要具备独立身份: + +- 谁创建了这个 Agent? +- 它代表哪个用户或组织执行任务? +- 它可以调用哪些工具? +- 它能访问哪些文件和知识库? +- 它的动作如何审计? +- 它的权限如何撤销? + +这个阶段的核心问题是:Agent 能代表人做到哪一步? + +## 第七阶段:AI 模型与知识保护 + +AI 应用真正敏感的资产,不只在数据库里。 + +提示词、系统指令、RAG 知识库、训练或微调数据、工具调用记录、业务上下文、用户上传文件,都可能承载企业知识和权限边界。 + +如果这些内容被错误注入上下文、被越权检索、被日志泄露,或者被 Agent 带入不该调用的工具链路,风险就会从“数据泄露”升级成“自动化误执行”。 + +这个阶段的核心问题是:模型和 Agent 能携带哪些知识去执行动作? + +## 当下的架构重点 + +AI Agent 安全至少需要四个控制面: + +1. 身份控制面:区分人、应用、Agent、工具和服务账号。 +2. 知识控制面:按组织、项目、用户、任务隔离 RAG 和文件上下文。 +3. 工具控制面:对每个工具调用做授权、参数约束、审批和限流。 +4. 审计控制面:记录从用户意图到 Agent 计划、工具调用、结果产物的完整链路。 + +这四个控制面缺一不可。 + +只有身份,没有知识隔离,Agent 仍可能读到不该读的内容。 + +只有网关,没有工具授权,Agent 仍可能用正确入口做错误动作。 + +只有日志,没有可撤销能力,事故发生后仍然难以止损。 + +## 结语 + +安全边界的演进,本质上是计算形态的演进。 + +单机时代保护机器,网络时代保护边界,Web 时代保护业务入口,云时代保护身份,Zero Trust 时代保护每一次访问。 + +AI Agent 时代,需要保护的是:一个携带知识、拥有工具、能代表人执行任务的智能体。 + +未来的企业安全,不只是“谁能访问系统”,而是: + +谁能携带什么知识,以什么身份,替谁执行什么动作。 diff --git a/docs/cases/ai-security-evolution-content-scenario/x-copy.md b/docs/cases/ai-security-evolution-content-scenario/x-copy.md new file mode 100644 index 00000000..e316dbe5 --- /dev/null +++ b/docs/cases/ai-security-evolution-content-scenario/x-copy.md @@ -0,0 +1,59 @@ +# X 风格文案:安全边界正在迁移 + +## 长帖 + +安全的主线,正在从“保护机器”迁移到“约束会行动的智能体”。 + +| 演进路径 | 当下 | +| --- | --- | +| 单机权限 | 终端只是入口,真正的风险在身份、数据和任务链路。 | +| 网络边界 | 边界不再等于防火墙,而是 API、设备、身份、供应链和运行时。 | +| Web 安全 | 页面漏洞还在,但攻击面已经扩展到业务流、插件和自动化调用。 | +| 云身份 | IAM 成为默认控制平面,权限漂移和密钥暴露是高频事故源。 | +| Zero Trust | 不再默认信任网络位置,改为持续验证、最小权限、上下文授权。 | +| AI Agent 身份 | Agent 代表人执行任务,必须有独立身份、授权边界和审计链。 | +| AI 模型与知识保护 | 模型、提示词、RAG 知识库和工具调用记录,都变成资产边界。 | + +过去,我们问:这台机器谁能登录? + +后来,我们问:这个服务从哪个网段进来? + +再后来,我们问:这个用户、这个设备、这个会话、这个 API 调用是否可信? + +现在必须继续往前问: + +这个 AI Agent 是谁授权的?它能读哪些知识?能调用哪些工具?能代表人做到哪一步?失败后谁负责?如何撤销?如何审计? + +AI 时代的安全不是给模型外面套一层网关就结束了。 + +真正的边界在三处: + +1. 身份边界:人、应用、Agent、工具都要有可区分身份。 +2. 知识边界:RAG、提示词、文件、业务语料要按权限进入上下文。 +3. 行动边界:Agent 调工具、改数据、发请求、创建任务都要可授权、可追踪、可撤销。 + +一句话: + +安全从“谁能访问系统”升级为“谁能携带什么知识,以什么身份,替谁执行什么动作”。 + +## 短帖 + +安全边界的演进: + +单机权限 -> 网络边界 -> Web 安全 -> 云身份 -> Zero Trust -> AI Agent 身份 -> AI 模型与知识保护 + +当下最重要的变化是: + +AI Agent 不只是一个聊天入口,而是会代表人调用工具、读取知识、执行任务的新主体。 + +所以安全问题也变了: + +不是只问“用户能不能访问”,而是要问“Agent 能不能代表用户把这件事做完”。 + +身份、知识、工具、审计,会成为 AI 应用的四个基本控制面。 + +## 发布建议 + +- 适合配一张横向演进图。 +- 首条评论可补充:Agent 身份不是模型账号,而是任务执行主体。 +- 互动问题:你们现在的 AI Agent 权限,是按人、按应用,还是按任务隔离? diff --git a/docs/cases/ai-security-evolution-content-scenario/xhs-copy.md b/docs/cases/ai-security-evolution-content-scenario/xhs-copy.md new file mode 100644 index 00000000..202c6c70 --- /dev/null +++ b/docs/cases/ai-security-evolution-content-scenario/xhs-copy.md @@ -0,0 +1,59 @@ +# XHS 风格文案:AI 时代,安全边界真的变了 + +## 标题备选 + +- AI Agent 时代,安全边界不再只是账号和防火墙 +- 从单机权限到模型知识保护,一张表看懂安全演进 +- 为什么 AI 应用上线后,权限体系要重新设计? + +## 正文 + +最近整理 AI Agent 安全架构时,我发现很多团队还在用传统应用的方式理解 AI 安全: + +有账号、有网关、有日志,就觉得差不多了。 + +但 AI Agent 的问题是:它不只是“回答问题”,它会读取知识、调用工具、创建任务、修改文件、访问外部系统。安全边界因此发生了迁移。 + +| 演进阶段 | 当下应该关注什么 | +| --- | --- | +| 单机权限 | 终端不再是完整边界,只是身份和任务链路的入口。 | +| 网络边界 | 防火墙仍重要,但 API、设备、身份、供应链才是新组合面。 | +| Web 安全 | 不能只看页面漏洞,还要看业务流、插件和自动化调用。 | +| 云身份 | IAM 是控制平面,重点防权限漂移、密钥暴露、跨账号误用。 | +| Zero Trust | 默认不信任位置,持续验证身份、设备、上下文和行为。 | +| AI Agent 身份 | Agent 要有自己的身份、权限范围、审计链和撤销机制。 | +| AI 模型与知识保护 | 模型、提示词、知识库、工具调用记录都是需要保护的资产。 | + +我觉得最关键的是这句话: + +AI 安全不是“给模型加一层登录”,而是要回答: + +这个 Agent 是谁? + +它代表谁? + +它能读哪些知识? + +它能调用哪些工具? + +它执行过什么动作? + +出问题后能不能撤销和追责? + +## 适合团队自查的 5 个问题 + +1. Agent 是否有独立身份,而不是复用某个管理员 token? +2. RAG 知识库是否按用户、组织、项目做了权限隔离? +3. 工具调用是否有最小权限和审批边界? +4. Agent 执行动作是否能完整审计到“人、任务、工具、结果”? +5. 提示词、业务语料、调用记录是否被当成资产管理? + +## 结尾 + +AI 应用越像一个员工,安全体系就越不能只把它当成一个接口。 + +下一阶段的企业安全,会从“保护系统入口”走向“治理智能体行为”。 + +## 标签 + +#AI安全 #Agent安全 #ZeroTrust #云安全 #企业安全 #知识库安全 #AI产品设计 diff --git a/docs/cases/core-integration-manual-cases.md b/docs/cases/core-integration-manual-cases.md index b1fa7ac0..2605c83f 100644 --- a/docs/cases/core-integration-manual-cases.md +++ b/docs/cases/core-integration-manual-cases.md @@ -102,6 +102,29 @@ - 产物路径 - 截图点:artifact 列表与连续追问结果 +### `MANUAL-LOCAL-001A` AI 安全演进多平台内容生产 + +- 前置条件 + - 当前线程为空白或新建线程 + - 当前 workspace 允许写入 Markdown 与 PPTX artifact +- 操作步骤 + 1. 输入 `docs/cases/ai-security-evolution-content-scenario/README.md` 中的 App 手动测试提示词 + 2. 等待任务完成 + 3. 确认生成 X / XHS / 微信文章三份 Markdown 文件 + 4. 确认生成一份 PPTX 文件 + 5. 在同一线程继续追问“把 X 风格文案压缩到 280 字以内” +- 期望结果 + - 四个产物都写回当前线程 workspace + - artifact 区显示 3 个 `.md` 文件和 1 个 `.pptx` 文件 + - 三份 Markdown 共享同一张安全演进对照表,但文体不同 + - PPTX 至少包含封面、演进总览、当下判断和行动清单 + - follow-up 基于同一线程上下文修改,不新建孤立线程 +- 建议记录项 + - 线程 ID 或线程标题 + - 输入提示词 + - 四个产物路径 + - artifact 区截图 + ### `MANUAL-LOCAL-002` `word-docx` - 前置条件 diff --git a/docs/compliance/dsa-trader-identity/en_dsa_identity_statement_haitao_pan.docx b/docs/compliance/dsa-trader-identity/en_dsa_identity_statement_haitao_pan.docx new file mode 100644 index 00000000..afcf5540 Binary files /dev/null and b/docs/compliance/dsa-trader-identity/en_dsa_identity_statement_haitao_pan.docx differ diff --git a/docs/compliance/dsa-trader-identity/en_dsa_identity_statement_haitao_pan.pdf b/docs/compliance/dsa-trader-identity/en_dsa_identity_statement_haitao_pan.pdf new file mode 100644 index 00000000..a736e8d5 Binary files /dev/null and b/docs/compliance/dsa-trader-identity/en_dsa_identity_statement_haitao_pan.pdf differ diff --git a/docs/compliance/dsa-trader-identity/zh_dsa_identity_statement_haitao_pan.docx b/docs/compliance/dsa-trader-identity/zh_dsa_identity_statement_haitao_pan.docx new file mode 100644 index 00000000..aeb62ea2 Binary files /dev/null and b/docs/compliance/dsa-trader-identity/zh_dsa_identity_statement_haitao_pan.docx differ diff --git a/docs/compliance/dsa-trader-identity/zh_dsa_identity_statement_haitao_pan.pdf b/docs/compliance/dsa-trader-identity/zh_dsa_identity_statement_haitao_pan.pdf new file mode 100644 index 00000000..1ea7fa0f Binary files /dev/null and b/docs/compliance/dsa-trader-identity/zh_dsa_identity_statement_haitao_pan.pdf differ diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8d812b83..a9971d07 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -204,6 +204,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, F190BC0EA83544A81E2F67D3 /* [CP] Embed Pods Frameworks */, + A1B2C3084F0A000100000002 /* Generate Missing Framework dSYMs */, ); buildRules = ( ); @@ -368,6 +369,26 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + A1B2C3084F0A000100000002 /* Generate Missing Framework dSYMs */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Generate Missing Framework dSYMs"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/bash \"${PROJECT_DIR}/../scripts/ensure-framework-dsyms.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 8d54f9e0..70e474d5 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -450,7 +450,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/bash \"${PROJECT_DIR}/../scripts/macos_generate_missing_dsyms.sh\"\n"; + shellScript = "/bin/bash \"${PROJECT_DIR}/../scripts/ensure-framework-dsyms.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ diff --git a/scripts/check-apple-export-compliance.sh b/scripts/check-apple-export-compliance.sh index 0565783c..4203caef 100755 --- a/scripts/check-apple-export-compliance.sh +++ b/scripts/check-apple-export-compliance.sh @@ -58,10 +58,10 @@ resolve_artifact_plist() { return 0 fi if [[ -d "$input_path" && "$input_path" == *.xcarchive ]]; then - local plist_path="" - plist_path="$(find "$input_path/Products/Applications" -maxdepth 3 -name Info.plist | head -n 1)" - if [[ -n "$plist_path" ]]; then - printf '%s\n' "$plist_path" + local app_path="" + app_path="$(find "$input_path/Products/Applications" -maxdepth 1 -name '*.app' -type d | head -n 1)" + if [[ -n "$app_path" && -f "$app_path/Info.plist" ]]; then + printf '%s\n' "$app_path/Info.plist" return 0 fi fi diff --git a/scripts/ensure-framework-dsyms.sh b/scripts/ensure-framework-dsyms.sh index 9e2143a6..df8a0192 100755 --- a/scripts/ensure-framework-dsyms.sh +++ b/scripts/ensure-framework-dsyms.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -# Keep release/profile uploads resilient by generating missing framework dSYMs -# after embed phases. This is a no-op for debug builds. +# Generate the dSYM that App Store validation expects for the vendored +# objective_c native-asset framework after Xcode/CocoaPods embed it. if [[ "${CONFIGURATION:-}" != "Release" && "${CONFIGURATION:-}" != "Profile" ]]; then exit 0 fi @@ -29,12 +29,7 @@ for framework_path in "${frameworks_dir}"/*.framework; do binary_path="${framework_path}/${framework_name}" [[ -f "${binary_path}" ]] || continue - # Most Flutter and pod frameworks already produce dSYMs in normal archive - # flow. Keep this pass narrow to known stragglers observed in distribution. - case "${framework_name}" in - objective_c|App|A) ;; - *) continue ;; - esac + [[ "${framework_name}" == "objective_c" ]] || continue dsym_path="${DWARF_DSYM_FOLDER_PATH}/${framework_name}.framework.dSYM" if [[ -d "${dsym_path}" ]]; then diff --git a/scripts/macos_generate_missing_dsyms.sh b/scripts/macos_generate_missing_dsyms.sh deleted file mode 100644 index a4f34cd1..00000000 --- a/scripts/macos_generate_missing_dsyms.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if [[ "${DEBUG_INFORMATION_FORMAT:-}" != "dwarf-with-dsym" ]]; then - exit 0 -fi - -frameworks_dir="${TARGET_BUILD_DIR:-}/${WRAPPER_NAME:-}/Contents/Frameworks" -dsyms_dir="${DWARF_DSYM_FOLDER_PATH:-}" - -if [[ -z "${frameworks_dir}" || -z "${dsyms_dir}" || ! -d "${frameworks_dir}" ]]; then - exit 0 -fi - -shopt -s nullglob - -for framework in "${frameworks_dir}"/*.framework; do - framework_name="$(basename "${framework}")" - binary_name="${framework_name%.framework}" - binary_path="${framework}/${binary_name}" - - if [[ ! -f "${binary_path}" ]]; then - binary_path="${framework}/Versions/A/${binary_name}" - fi - - if [[ ! -f "${binary_path}" ]]; then - continue - fi - - if ! file "${binary_path}" | grep -q "Mach-O"; then - continue - fi - - dsym_path="${dsyms_dir}/${framework_name}.dSYM" - if [[ -d "${dsym_path}" ]]; then - continue - fi - - echo "Generating missing dSYM for ${framework_name}" - rm -rf "${dsym_path}" - uuid_output="$(xcrun dwarfdump --uuid "${binary_path}" 2>/dev/null || true)" - if [[ -z "${uuid_output}" ]]; then - continue - fi - - if ! xcrun dsymutil "${binary_path}" -o "${dsym_path}" >/dev/null 2>&1; then - rm -rf "${dsym_path}" - fi -done