关于 audit-xcode-security-settings
用于审计 Xcode 项目的安全构建设置和权限,并规划逐步加固。面向维护 Xcode 项目的团队;它会先生成可审阅的计划,仅在获批后应用更改,并提供设置、功能和采用顺序方面的指导。
主要功能
- 01审计构建设置和权限
- 02规划渐进式安全加固
- 03检查特定目标的设置
- 04仅应用已批准的更改
- 05使用 Xcode 工具操作项目
适用场景
- 01评估 Xcode 项目的安全状况
- 02规划 Enhanced Security 的采用
- 03按目标检查权限变更
- 04应用已批准的加固设置
MCP 相关
该技能会在可用时要求使用 MCP 服务提供的 Xcode 工具,包括项目搜索、读取、更新和目标枚举。它本身未说明提供 MCP 服务接口。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tartinerlabs/ skills --skill audit-xcode-security-settings安装后在 Claude Code 中输入/audit-xcode-security-settings确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/additional-settings.mdadoption-strategy.mdchecked-pointer-arithmetic.mdcpp-hardening.mddecision-document.mdenhanced-security.mdhardware-memory-tagging.mdpointer-authentication.mdreading-build-settings.mdreadonly-platform-memory.mdruntime-restrictions.mdsecurity-compiler-warnings.mdsecurity-settings-reference.mdstack-zero-init.mdtyped-allocators.mduniversal-binaries-for-libraries.mdscripts/filter_build_settings.py详细介绍
审计 Xcode 安全设置
评估 Xcode 项目的安全态势,并逐步启用安全构建设置和授权 — 从广泛适用的警告,到 Enhanced Security 加固。
工具偏好
当 XcodeGlob、XcodeGrep、XcodeRead、XcodeLS 和 XcodeUpdate 工具可用时,ALWAYS 使用它们。不要回退到 Bash 文件系统工具(ls、find、cat、grep)来了解项目。它们会触发额外的权限提示,并绕过项目作用域。
工具名称可能带有 MCP 服务前缀。 这些工具由某个 MCP 服务托管,其名称因环境而异(xcode-mcp、xcode-tools、xcode 等),因此它们的完全限定名类似于 mcp__<server>__XcodeGlob。某些执行环境会注册短别名(仅 XcodeGlob);其他环境只暴露带前缀的形式。不要硬编码特定的服务名称。首次调用时,使用可用工具注册表所公布的任一形式 — 查找一次前缀,然后在本次会话的其余部分复用。如果短名称调用因未知工具错误而失败,不要猜测前缀:在注册表中查找它,然后用完整名称重试。
- XcodeGlob 用于文件发现 — 项目内文件禁止使用
find。 - XcodeGrep 用于内容搜索 — 项目内文件禁止使用
grep/rg。 - XcodeRead 用于读取文件内容 — 项目中已注册的文件禁止使用
cat/Read。 - XcodeLS 用于列出目录 — 项目内任何路径禁止使用
ls。 - XcodeUpdate 用于就地编辑项目已注册的文本文件(xcconfig 文件、源文件)— 与内置
Edit工具具有相同的filePath/oldString/newString(+ 可选replaceAll)签名,但接受 Xcode 工作区相对路径。项目中已注册的文件禁止使用Edit。不要使用XcodeUpdate/Edit/plutil添加或更新.entitlements键 — 请使用AddEntitlement。 - AddEntitlement 用于添加或更新目标的授权 — 传入
targetName、entitlementKey、entitlementValueType(bool/string/int/stringArray/dictionary)以及值。进行授权更改时始终优先使用它;它只能添加或更新,不能删除键。 - XcodeListTargets 用于枚举目标 — 不要手动解析
project.pbxproj。直接返回每个目标的PRODUCT_TYPE_IDENTIFIER和角色标志(IS_AGGREGATE、IS_TEST_TARGET、IS_APP_EXTENSION、SUPPORTS_HOSTING_TESTS)。
项目根目录和名称已经在系统提示词上下文中。 开始前不要运行 ls 来"验证"项目布局。系统提示词已经告诉你工作目录和项目结构。
XcodeGlob 的空结果不是失败。 .xcodeproj 和 .xcworkspace 不会作为文件被索引到 Xcode 工作区中 — XcodeGlob "**/*.xcodeproj" 正确返回 0 个匹配。请改用系统提示词上下文中的项目名称。不要回退到文件系统 ls/find。
所有 Xcode* 工具都接受 Xcode 工作区相对路径。 XcodeGlob、XcodeGrep、XcodeRead、XcodeLS、XcodeUpdate、XcodeWrite 和 XcodeRM 将其路径参数 — 以及返回的路径 — 解释为相对于 Xcode 工作区根目录(即你在 Project Navigator 顶部看到的内容)。不是 git 仓库根目录;也不是 .xcodeproj 包。用户在 Xcode 中看到的任何内容(授权、xcconfig、计划和决策文档、源文件)都可以通过其工作区相对路径访问到;将该路径原样传给这些工具,不要为其构造绝对文件系统路径。
要读取或编辑特定文件:
- 优先使用带工作区相对路径的
XcodeRead/XcodeUpdate。XcodeRead也能读取.entitlementsplist — 它们是项目已注册的文件,可以像任何源文件一样导航 — 因此请用这种方式读取它们。要添加或更新授权,请使用AddEntitlement,而不是XcodeUpdate。 对于 entitlements 文件,绝不手动推导路径。 每个 target 的权威 entitlements 路径是其CODE_SIGN_ENTITLEMENTS构建设置求值后的值 —— 通过GetTargetBuildSettings获取并原样使用。不要解析project.pbxproj来重建路径,也不要使用**/*.entitlements通配符匹配:磁盘上可能存在未被任何 target 引用的孤立.entitlements文件。一个 entitlements 文件可以被多个 target 引用。
仅在 Xcode 工具无法完成的操作(例如 git 操作)中才回退到使用 Bash。
内置参考文档
所有参考资料都位于与本文件同级的 references/ 目录下。
references/security-settings-reference.md—— 本技能跟踪的安全构建设置与 entitlements 的规范列表,包含加固值、CLI 标志和语言适用范围。references/reading-build-settings.md——GetTargetBuildSettingsschema、过滤脚本用法、审计表构建,以及“已加固” / “有意禁用” 判定条件。references/enhanced-security.md—— Enhanced Security 能力:构建设置、entitlements、支持的产品类型。references/pointer-authentication.md—— arm64e 指针签名:支持的平台、使用方兼容性说明。references/universal-binaries-for-libraries.md—— 面向库/框架 target 的通用二进制指南(指针认证会自动添加arm64e切片)、符合条件的产品类型、XCFramework 指南。references/security-compiler-warnings.md—— Enhanced Security 启用的安全相关编译器警告和设置。references/cpp-hardening.md—— C++ 标准库加固(CLANG_CXX_STANDARD_LIBRARY_HARDENING)与边界安全缓冲区(ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS)。references/typed-allocators.md—— 类型感知分配器支持与hardened-heap子选项。references/stack-zero-init.md—— 运行时自动对栈变量进行零初始化。references/readonly-platform-memory.md—— dyld 状态的只读保护。references/runtime-restrictions.md—— dylib 与 Mach message 平台限制。references/hardware-memory-tagging.md—— MTE entitlements 与支持的硬件。references/checked-pointer-arithmetic.md—— 受检指针运算(CPA2)。references/additional-settings.md—— 默认值之外的可选诊断设置(可能有更多误报)。references/adoption-strategy.md—— 验证 Enhanced Security 功能的推荐顺序(从最低风险到最高投入)。references/decision-document.md—— 如何维护持久化的xcode-security-settings.md决策文档。
本技能附带一个辅助脚本:
scripts/filter_build_settings.py—— 将GetTargetBuildSettingsJSON 过滤为security-settings-reference.md中跟踪的宏。用法参见references/reading-build-settings.md。
常见失败模式
| 现象 | 原因 | 正确处理方式 |
|---|---|---|
对 XcodeGlob 等工具调用失败,报错 "unknown tool" / "tool not found" | 在此环境中,harness 仅以带 MCP 前缀的完整名称(mcp__<server>__XcodeGlob)注册这些工具 | 在可用工具注册表中查找前缀,用完整名称重试一次,然后在整个会话中继续使用完整名称。 |
XcodeGlob "**/*.xcodeproj" 返回 0 个匹配项 | .xcodeproj 本身不是项目索引中的文件 | 使用系统上下文中的项目名称;不要退回到 find 或 ls |
对确实位于 .xcodeproj / .xcworkspace 包内的文件(例如 WorkspaceSettings.xcsettings)执行 XcodeRead <workspace-relative-path> 失败 | 该文件不是项目导航器成员 | 使用系统上下文中的项目根目录将其转换为文件系统绝对路径,然后使用 Read / Edit。(不适用于 .entitlements 文件——那些是可导航的。) |
对手动推导出的 entitlements 路径执行 Read 返回 File does not exist | 该路径是根据 project.pbxproj 的 group 嵌套结构重建的,或通过 glob **/*.entitlements 猜测的。Xcode 对某个 target 的 entitlements 的权威路径是 CODE_SIGN_ENTITLEMENTS 的求值结果,而不是导航器显示的内容。 | 通过 GetTargetBuildSettings 查找该 target 的 CODE_SIGN_ENTITLEMENTS(或从审计表中读取),并将其求值结果用作路径。 |
工作流
阶段 1:简报
在开始任何工作之前,用两三句话告诉用户——这个技能是什么、它会做什么,以及大致需要他们投入多少时间和注意力:
- 它是什么。 对项目 Xcode 安全构建设置和 entitlements 进行审计(编译器警告、Enhanced Security entitlements、指针认证、受检指针运算、库的通用二进制文件等)。
- 会发生什么。 该技能分为两部分,长度大致相当。首先是 规划:我分析项目并在项目根目录写下一个可编辑的计划文件供你审阅。然后是 执行:一旦你选择 Run,我只应用你已批准的更改。在你选择 Run 之前,不会修改任何内容。
- 时间投入。 规划 需要我几分钟的分析(对于有许多 target 的项目会更久——我会同步说明进度),外加你审阅计划文件的时间,你可以快速浏览也可以仔细阅读——由你决定。执行 耗时大致相同:应用已批准的更改,其中有两处可能会暂停以等待你的输入——询问步骤(如果有故意禁用的设置且其理由没有文档记录),以及最后关于是否将计划文件保留在项目中作为记录的 yes/no 确认。 整个过程通常需要约 15-30 分钟,大致平均分配到两部分,具体取决于构建 target 的数量以及你审阅和批准计划所需的时间。
保持简洁——用户调用该技能时已经知道自己想要一次审计。 简报的存在是为了让他们有合理的预期。
然后检查源代码控制。 如果满足以下任一条件,则项目有 源代码控制:
- Environment 块的
Is a git repository字段为true,或 - 在项目根目录进行一次文件系统检查,发现以下任意一项:
.git、.hg、.svn、.bzr、.fslckout、_FOSSIL_、CVS。
否则,项目 没有源代码控制。记录此状态——阶段 4 步骤 3 会用它来决定是否在计划文件中包含 ⚠️ 引用块。
在完成简报后,通过 AskUserQuestion 暂停。如果项目有源代码控制:
- 开始审计 —— 进入阶段 2。
- 取消 —— 以 "Cancelled — no changes applied." 退出。
如果项目 没有源代码控制,先告诉用户:"强烈建议在继续之前设置源代码控制。该技能会修改构建设置和 entitlements;如果没有类似 Git 的工具,回滚需要手动操作,而且你也没有一种干净的方式来审阅差异。Xcode 内置支持 Source control management" 然后询问:
- 先设置源代码控制(推荐) —— 以 "Set up source control and re-run the skill." 退出。
- 在没有源代码控制的情况下继续 —— 进入阶段 2;阶段 4 步骤 3 会在计划文件中再次提示无源代码控制的提醒。
- 取消 —— 以 "Cancelled — no changes applied." 退出。
暂停的存在是为了让简报在屏幕上停留足够长的时间以便阅读;否则 Discovery 和 Analysis 的输出会把它滚走。在没有源代码控制时尽早失败,可以避免花几分钟进行 discovery 和 analysis,结果用户却在计划批准时退出。
阶段 2:Discovery
阅读系统提示中的 Environment 块。相关字段:
Primary working directory—— 项目根目录(项目名称即为其 basename)。Is a git repository—— 项目是否被 git 跟踪(供阶段 1 的源代码控制检查使用)。
跟踪进度
每一项需要执行的按目标 / 按设置的操作都必须有独立的任务,以保证透明性。
- 阶段 1(简报)是一个任务,当用户选择 Begin audit / Cancel 时完成。
- 阶段 3 为每个目标创建一个任务(
Audit <target>);一旦阶段 3 既生成了按目标的审计表行,又(对于受支持的产品类型)生成了该目标的 Enhanced-Security 类别,该任务即关闭。阶段 3 将所有按目标的状态存储在任务的description字段中(格式见阶段 3 步骤 4),以便后续阶段可以通过TaskGet读回。阶段 4–7 读取这些任务描述。 - 阶段 4(计划与批准)是一个任务,当用户选择 Run/Cancel 时完成。
- 在 Run 时,阶段 4 步骤 5 解析计划并创建细粒度任务。对于每个应用任务,它将该目标的增量(从对应的
Audit <target>任务的description中提取)嵌入到应用任务自己的description中,这样阶段 5 就不必再次查找。- 对于每个被勾选的 Enhanced Security 子项:
- Enable Enhanced Security:
Enable Enhanced Security at project level(一个任务)。在仅含 pbxproj 的项目上,此任务封装了阶段 5 步骤 1a 中描述的引导并验证流程。 - Update entitlements:每个需要更改的目标对应一个
Apply Enhanced Security entitlements to <target>。 - Hardware memory tagging:
Apply Hardware Memory Tagging(一个任务;在内部遍历受支持的目标)。 - Checked pointer arithmetic:
Apply Checked Pointer Arithmetic(一个任务;在内部遍历受支持的目标)。
- Enable Enhanced Security:
- 对于每个被勾选的 Warnings 子项:
- 如果该子项被勾选,则
Apply Compiler Warnings。 - 如果该子项被勾选,则
Apply Static Analyzer Warnings。 - 如果该子项被勾选,则
Apply Clang-Tidy Warnings。
- 如果该子项被勾选,则
- 如果被勾选,则
Apply Additional Diagnostic Settings。 - 如果被勾选,则
Emit Bounds Safety Adoption guidance。 - 每个阶段 6 候选项对应一个
Inquire about <MACRO> on <target>(仅当 "Inquire about disabled settings" 被勾选时)。 Report and update decision document。Prompt to remove plan file—— 始终最后执行;在错误路径上也会触发。
- 对于每个被勾选的 Enhanced Security 子项:
进入每个阶段或子步骤时:
- 用纯英文打印一行,指明阶段或子步骤的名称 —— 绝不打印阶段编号。使用阶段的名称(例如 "▶ Briefing"、"▶ Analyzing project"、"▶ Plan & Approve"、"▶ Applying settings");对于子步骤,指明正在进行的操作(例如 "▶ Detecting languages"、"▶ Building the audit table")。
- 将任务更新为
in_progress。
完成每个阶段或子步骤时:
- 打印一行:"✓ <相同标签>",如适用则附上简要结果(例如 "✓ Detecting languages: C and Swift found.")。
- 将任务更新为
completed。
应用步骤可以在完成自己的任务之前,在其任务的 description 中记录所做的事情,每个目标一行。阶段 7 读取这些行,而不是重新推导状态或抓取先前的输出。
阶段 3:分析项目和设置
无用户交互。在后台收集事实。
步骤 1:定位现有的决策文档
XcodeGlob '**/xcode-security-settings.md'。如果找到,则 XcodeRead 它,并提取语言以及先前设置决策及其状态和理由。这为后续阶段提供依据。
第 2 步:检测语言
每种语言执行一次 XcodeGlob。结果为空并不代表失败——将该语言记为不存在。
**/*.c→ C**/*.cpp、**/*.cxx、**/*.cc→ C++**/*.m→ Objective-C**/*.mm→ Objective-C++**/*.swift→ Swift
Objective-C++ 意味着 C++ 也存在。 .mm 文件包含 C++ 源代码,因此当检测到 Objective-C++ 时,任何以“存在 C++”为条件的审计(C++ 标准库加固、bounds-safe-buffers 指引、CLANG_ANALYZER_OSOBJECT_C_STYLE_CAST 等)都必须触发,即使不存在任何 .cpp/.cxx/.cc 文件。
文件扩展名并非权威依据。 Xcode 项目可以通过 project.pbxproj 中的 explicitFileType / lastKnownFileType 覆盖文件的编译语言——最常见的是将 .m 文件标记为 sourcecode.cpp.objcpp(按 Objective-C++ 编译),或将 .h 标记为 sourcecode.c.h / sourcecode.cpp.h。为捕获这些覆盖,请通过 Bash 执行 grep -E 'sourcecode\.cpp\.[a-zA-Z0-9]+' <project-root>/<ProjectName>.xcodeproj/project.pbxproj。project.pbxproj 是 .xcodeproj bundle 内 Xcode 的项目描述文件;请直接读取它。将任何 sourcecode.cpp.objcpp 匹配同时视为 Objective-C++ 和 C++;将任何其他 sourcecode.cpp.* 匹配视为 C++。
第 3 步:构建审计表
列定义、构建方法以及规范判定条件(“已加固”“默认关闭”“被有意禁用”)见 references/reading-build-settings.md。概览如下:
- 调用
XcodeListTargets枚举 target。跳过IS_AGGREGATE = true的条目(它们没有 product type)。为每个剩余的 target 记录TARGET_NAME、CONTAINING_PROJECT和PRODUCT_TYPE_IDENTIFIER——第 4 步直接按PRODUCT_TYPE_IDENTIFIER对 target 分类(不做推断)。 - 对每个 target:
TaskCreate "Audit <target>",设为 in_progress。调用GetTargetBuildSettings,对生成的 JSON 运行scripts/filter_build_settings.py,并为每个被跟踪的宏记录evaluatedValue和setAtTargetLevel(如果 JSON 中存在targetValue则为yes)。将这些行保留好,准备在第 4 步写入任务的description(连同分类一起)。让任务保持 in_progress——第 4 步会将其关闭。 - 使用过滤正则分两轮扫描显式设置:对
*.xcconfig执行XcodeGrep,并通过 Bash 执行grep -nE '<filter regex>' <project-root>/<ProjectName>.xcodeproj/project.pbxproj。project.pbxproj是.xcodeprojbundle 内 Xcode 的项目描述文件;请直接读取它。为每个宏记录numMatchesInXCConfigs、numMatchesInPbxproj以及 file:line 引用。 - 审计表是连接后的视图:每个(target,被跟踪宏)对应一行。第 4、5、6 阶段都使用此表;不再重新获取其他内容。
此步骤的规模随 target 数量增长:每次 GetTargetBuildSettings 调用需要数秒,而每个 target 都要调用一次。在约有十个或更多 target 的项目上,这可能耗时几分钟。
第 4 步:各 target 的 Enhanced-Security 状态
根据第 3 步记录的 PRODUCT_TYPE_IDENTIFIER,将每个 target 归入以下三类之一:
- 支持 Entitlements——product type 位于
references/enhanced-security.md的 "Supported Product Types" 列表中(applications、XPC services、system extensions、driver extensions [仅构建设置]、tools)。读取该 target 的CODE_SIGN_ENTITLEMENTS构建设置中路径所指向的 entitlements plist,并将该 target 分类为 Up-to-date、Partial、Off 或 No-entitlements-file。多个 target 可以共享同一个CODE_SIGN_ENTITLEMENTS路径;请分别独立地对每个 target 分类。 - Library/framework——product type 位于
references/universal-binaries-for-libraries.md中列出的合格集合中(frameworks、static frameworks、static libraries、dynamic libraries)。不读取 entitlements。第 5 阶段将为这些检查 universal-binary 配置。 - Skipped——其他任何类型(test bundles、app extensions 等)。
现在把 Phase 3 了解到的关于此目标的所有内容,通过
TaskUpdate写入Audit <target>任务的description,然后将其设为completed。该 description 保存 Phase 4–6 稍后需要查阅的整个按目标状态。格式:
Category: <category> [/ <sub-state>] # e.g. "Entitlements-supported / Partial", "Library/framework", "Skipped"
Entitlements path: <evaluated CODE_SIGN_ENTITLEMENTS> # omit for Library/framework and Skipped
SDKROOT: <value>
SUPPORTED_PLATFORMS: <value>
Missing entitlements: <comma-separated short names> # Entitlements-supported only; required and default-ON keys the target lacks; omit if empty
Checked pointer arithmetic: <eligible-entitlement | eligible-slice-only | enabled | not-eligible: <reason>> # Entitlements-supported and Library/framework targets
Deliberately-disabled: <MACRO>=<value> (<source>[+<source>...]), ... # one per disabled row; sources ⊆ {target-level, xcconfig, pbxproj} joined with '+' when more than one applies; omit the line entirely if none
Audit table:
<MACRO>=<value> setAtTargetLevel=<yes|no> numMatchesInXCConfigs=<n> numMatchesInPbxproj=<n> matchLocations=<citations>
...
Category 行放在最前面,这样任何展示片段摘要的客户端都能显示有意义的内容。Audit-table 块是 Step 3 中的按 (target, tracked macro) 行,以 key=value 形式呈现——每个被跟踪的宏一行,使用 references/reading-build-settings.md 中定义的规范列名。matchLocations 以贯穿全文使用的相同 <source>:<file>:<line>[,<line>...] 格式携带 file:line 引用。Skipped 目标获得此 Category 行、平台字段以及 Audit-table 块。Library/framework 目标获得这三项,外加 Checked pointer arithmetic: 行。两者都立即完成(不读取 entitlements)。
Checked pointer arithmetic 是此功能的唯一事实来源。 在此处计算一次,并记录四个值之一。之后每个阶段都读取此行,不再自行做任何判断。
enabled—— 对此目标无需任何操作。对于 Entitlements-supported 目标:entitlements 文件带有com.apple.security.hardened-process.checked-allocations.enforce-checked-pointer-arithmetic-overflow,且求值后的ENABLE_HARDWARE_CHECKED_POINTER_ARITHMETIC_SLICE为YES。对于 Library/framework 目标:求值后的ENABLE_HARDWARE_CHECKED_POINTER_ARITHMETIC_SLICE为YES—— 无需检查 entitlement。not-eligible: <reason>—— 取以下之一:platform,当SUPPORTED_PLATFORMS/SDKROOT既不匹配iphoneos也不匹配watchos时;opted out,当ENABLE_HARDWARE_CHECKED_POINTER_ARITHMETIC_SLICE对该目标为deliberately disabled时;no arm64e,当ENABLE_POINTER_AUTHENTICATION为deliberately disabled时;或outside the capability,当ENABLE_ENHANCED_SECURITY为deliberately disabled时。仅仅at default OFF的宏不构成理由 —— 启用 Enhanced Security 会解除它。outside the capability仅适用于 Entitlements-supported 目标:该 capability 提供 entitlement,而 library 不获取任何 entitlement。eligible-entitlement—— 一个 Entitlements-supported 目标,可以接受 checked pointer arithmetic 但尚未为其完全配置:它缺少arm64e.x1slice、checked-pointer-arithmetic entitlement,或两者皆缺。Step 4 应用缺失的那一项。eligible-slice-only—— 一个 Library/framework 目标,可以接受 checked pointer arithmetic 但没有该 build setting。这些目标没有 entitlement 那一半:entitlements 是按进程从主可执行文件授予的,因此 library 构建 slice,而消费方 app 的 entitlement 才是执行检查的依据。Step 4 仅应用 build setting。
该 key 永远不会列在 Missing entitlements 下,后者只保留必需的且默认开启的 key,因此它无法使目标变为 Partial,也无法到达 Step 1b。
在大型项目中,这会遍历许多 .entitlements plist —— 如果 Step 3 耗时明显,这一步也会如此。
Phase 4:规划与批准
此阶段生成一份量身定制、可编辑的计划文件,用户在任何更改发生之前审阅它。一旦批准,Phase 5–7 将端到端运行,不再有进一步提示。
Step 1:源代码控制状态
源代码控制已在 Phase 1 中检查,且用户当时已接受了任何无源代码控制的状态。Phase 4 Step 3 使用记录的状态来决定是否在计划文件中包含 ⚠️ 块引用。
步骤 2:如果一切都已配置,则跳过
对 Audit <target> 任务执行 TaskList,并对每个任务执行 TaskGet。如果所有默认勾选的计划项都已处于其目标状态,则提前退出:
- 每个 Enhanced-Security 类别(来自每个任务的
Category:行)均为 Up-to-date 或 Skipped。 - 没有任何任务的
Checked pointer arithmetic:行显示为eligible-entitlement或eligible-slice-only。 - 每个相关的 Warnings 设置(编译器、静态分析器和 clang-tidy)在每个适用的目标上均为
already hardened(依据每个任务的 Audit 表格块)。 - 没有任何任务的
Deliberately-disabled:行会产生一行(在下方 Phase-6 排除项之后)。
可选的后续操作(Additional diagnostic settings、Bounds safety adoption)不会阻止提前退出。报告 "Everything in scope is already configured" 并退出;不要写入计划文件。
步骤 3:写入计划文件
通过 XcodeWrite 在 Xcode 工作区的根目录创建 xcode-security-audit-plan.md(路径:xcode-security-audit-plan.md,无父分组)。XcodeWrite 既会将文件写入磁盘上 <project-root>/ 之下,又会在项目中注册该文件,以便用户可以直接从 Xcode 的 Project Navigator 打开它。
仅包含适用于该项目的项(参见下方的省略规则)。使用此模板——替换 <…> 中的占位符:
# Xcode Security Audit — Plan
**Project:** <name> · <N> targets · languages: <list>
**Generated:** <YYYY-MM-DD>
> ⚠️ **No source control detected.** This skill modifies build settings and entitlements.
> Without source control (e.g., Git), rollback requires manual undo. Consider [setting up source control](doc://com.apple.documentation/documentation/xcode/configuring-your-xcode-project-to-use-source-control) before picking **Run**.
Edit the items below — set what steps to perform now, or leave them unchecked to defer them. Questions about any item, or want a more detailed plan? Just ask — I'll answer, and can expand this plan on the points you care about before you decide.
## Phases
- **Enhanced Security** — the project's runtime-protection bundle. Apply to: <target list>. (Group — check the sub-items below.)
- [x] **[Enable Enhanced Security](doc://com.apple.documentation/documentation/Xcode/enabling-enhanced-security-for-your-app)** — sets `ENABLE_ENHANCED_SECURITY=YES` at the project level. (Your project doesn't use a project-level xcconfig — I'll walk you through enabling it in Xcode's Build Settings UI yourself, then verify by reading project file.)
- [x] **[Update entitlements](doc://com.apple.documentation/documentation/BundleResources/Entitlements/com.apple.security.hardened-process)** — adds the hardened-process entitlement family per target (Memory Safety, Runtime Protections).
- [x] **[Hardware memory tagging](doc://com.apple.documentation/documentation/BundleResources/Entitlements/com.apple.security.hardened-process.checked-allocations)** — adds the hardware memory tagging entitlement, in soft mode, on supported platforms (<target list filtered to MTE-supported platforms>).
- [x] **[Checked pointer arithmetic](doc://com.apple.documentation/documentation/BundleResources/Entitlements/com.apple.security.hardened-process.checked-allocations.enforce-checked-pointer-arithmetic-overflow)** — adds the arm64e.x1 slice and the entitlement to enforce pointer-arithmetic overflow checking (<target list filtered to arm64e.x1-supported platforms>). Run time enforcement requires hardware memory tagging enabled. Latent pointer-arithmetic bugs will terminate the app on capable hardware.
- **[Warnings](doc://com.apple.documentation/documentation/Xcode/build-settings-reference)** — additional diagnostics on all C/C++/ObjC targets. (Group — check the sub-items below.)
- [x] **Compiler warnings** — <N> settings promoting security-relevant compiler diagnostics (fire on every build).
- [x] **Static analyzer warnings** — <N> security checkers (run during Build and analyze).
- [x] **Clang-tidy warnings** — <N> clang-tidy-integrated checks (run during Build and analyze).
- [x] **Inquire about disabled settings** — <M> found (e.g., `<setting>=NO` on `<target>`). May trigger follow-up questions if no rationale is documented.
- [ ] **Additional diagnostic settings** — extra opt-in warnings/checkers beyond the defaults. Off by default: they surface more findings to review and can be noisier (more false positives).
- [ ] **[Bounds safety adoption](https://clang.llvm.org/docs/BoundsSafetyAdoptionGuide.html)** — pointer to a separate skill. No changes applied here.
## Decision document
The skill creates or updates `xcode-security-settings.md` to record every setting decision (kept, deferred, disabled, with rationale). Edit the path to relocate.
- Path: `xcode-security-settings.md`
仅当项目没有源代码控制时才包含 ⚠️ 引用块;否则省略。
仅当项目仅为 pbxproj(Phase 3 的项目级扫描未发现任何 *.xcconfig 文件)时,才在 Enable Enhanced Security 子项末尾包含括号内的说明;否则省略。
决策文档应与其余文档位于同一目录中,或位于项目层级。
项省略规则
当某一计划项不适用时,将其完全省略:
- Enhanced Security —— 仅当 Phase 3 步骤 4 中每个受支持产品类型类别均为 Up-to-date 或 Skipped,且没有任何任务的
Checked pointer arithmetic:行显示为eligible-entitlement或eligible-slice-only时才省略(连同所有子项)。否则必须启用 Enhanced Security。 - Enable Enhanced Security(子项)—— 当显示 Enhanced Security 时永不省略;仅末尾的 pbxproj-only 括号说明是有条件部分。
- Update entitlements(子项)—— 当显示 Enhanced Security 时永不省略。
- Hardware memory tagging(子项)—— 如果没有任何目标的
SUPPORTED_PLATFORMS/SDKROOT匹配macosx、iphoneos、iphonesimulator、watchos、xros或xrsimulator,则省略。 - Checked pointer arithmetic(子项)—— 如果没有任何任务的
Checked pointer arithmetic:行显示为eligible-entitlement或eligible-slice-only,则省略。 - Warnings —— 如果是纯 Swift,或者三个组中的所有设置在每个适用目标上均为
already hardened,则省略父项(及所有三个子项)。否则,当某一组(Compiler warnings、Static analyzer warnings 或 Clang-tidy warnings)中的所有设置在每个适用目标上均为already hardened,或者该组对检测到的语言没有适用设置时,省略该单个子项。 - Inquire about disabled settings —— 如果
deliberately disabled谓词不产生任何行,则省略。 - Additional diagnostic settings —— 永不省略;始终提供。
- Bounds safety adoption —— 如果 Phase 3 步骤 2 未检测到任何 C、C++ 或 Objective-C++(将
sourcecode.cpp.*覆盖计为 C++),则省略。
默认勾选状态
分组标题不带复选框。 带有子项的父级行——Enhanced Security 和 Warnings——只是普通的加粗分组标签,不是可勾选项;复选框由子项携带。这样可以避免出现父项已勾选、但其所有子项都未勾选这种含糊情况。其余每一项(包括没有子项的叶子项,如 Inquire about disabled settings、Additional diagnostic settings、Bounds safety adoption)都可勾选。
用户可以在选择 Run 之前编辑计划文件,以此切换 Phases 下的各项和子项。
第 4 步:请求批准
告诉用户:
“计划已写入
xcode-security-audit-plan.md并添加到 Xcode 项目——打开它进行查看。按需编辑——取消勾选或删除条目即可跳过它们;编辑决策文档路径即可将其迁移。准备好后,选择 Run。选择 Cancel 可在不做任何更改的情况下中止。在你选择 Run 之前,不会修改任何内容。”
然后通过 AskUserQuestion 以单选选项询问:
- Run — 继续进入“第 5 阶段”
- Cancel — 中止
步骤 5:处理响应
如果用户提出问题或要求更多细节,而不是选择 Run/Cancel:请回答该问题,查阅 Bundled Reference Documents 中的相关文档(例如,关于额外诊断设置可查阅 references/additional-settings.md)。如果他们希望将这些细节记录下来,请通过 XcodeUpdate 更新 xcode-security-audit-plan.md 以详细说明这些要点。然后重新显示步骤 4 的审批提示——在用户选择 Run 之前,不会应用任何内容。
如果选择 Cancel:运行最终的清理任务(Prompt to remove plan file,见下文“阶段 7:报告与决策文档”)。在 Cancel 时也会提供保留或移除的提示,因此用户放弃审计的选择不会与正常完成时悄然不同。报告“已取消——未应用任何更改”,并退出该 skill。
如果在重新读取时计划文件缺失(用户在响应之前已将其从磁盘删除),则将其视为 Cancel——并跳过 Prompt to remove plan file 任务(没有任何内容需要移除)。
如果选择 Run:执行 XcodeRead xcode-security-audit-plan.md。解析:
- 每个
- [x]或- [X]列表项都是已勾选条目;条目名称是加粗部分(位于**…**之间)。 - 带加粗但没有复选框的列表项(例如
- **Enhanced Security** …、- **Warnings** …)是分组标题,不是可勾选条目。它本身不会创建任何任务——由其已勾选的子条目驱动工作。不要将其视为已勾选或未勾选。 - 写为
- [ ]的条目以及从文件中删除的条目会被跳过——两者产生相同的跳过行为。 - 在“Decision document”标题下,
Path:后面的值是决策文档位置。
创建 Track Progress 中列出的细粒度任务:
- 对于每个
Apply Enhanced Security entitlements to <target>任务,将相应Audit <target>任务描述中的按目标差异(Category:、Entitlements path:、Missing entitlements:)复制到 apply 任务自己的描述中,以便阶段 5 从一个地方读取。 - Warnings 父行是标题,不是任务——它本身不会产生任何任务。每个已勾选的 Warnings 子条目会创建其对应的 apply 任务:Compiler warnings →
Apply Compiler Warnings,Static analyzer warnings →Apply Static Analyzer Warnings,Clang-tidy warnings →Apply Clang-Tidy Warnings。这与 Enhanced Security 父项映射到其子条目任务的方式一致。 - 要创建
Inquire about <MACRO> on <target>任务(仅当 Inquire about disabled settings 被勾选时),对Audit <target>任务执行TaskList,并对每个任务执行TaskGet;每个描述的Deliberately-disabled:行列出了该目标的候选行。过滤时应用下文记录的阶段 6 排除项。 - 创建
Report and update decision document任务时,将解析出的决策文档路径放入其描述中,以便阶段 7 从那里读取。
如果解析出的计划中没有任何已勾选条目,请立即运行最终的清理任务并报告“计划为空——无事可做。”
阶段 5:应用设置
在需要时,从每个 Audit <target> 任务的描述(Audit 表格块)中读取构建设置状态;每个目标的 apply 状态来自每个 apply 任务自己的描述。
如何应用构建设置:
- 项目使用
.xcconfig文件——直接编辑 xcconfig。同时支持项目级和目标级设置。 - 项目仅使用
.pbxproj——对于目标级设置,使用UpdateTargetBuildSetting。请用户启用项目级设置。一旦用户回复已设置,请使用 grep 对项目文件验证其设置是否正确。 - 混合——如果某个目标有
.xcconfig文件,则编辑该 xcconfig。否则,使用 Xcode 构建设置工具。绝不要引入新的配置方法。
ENABLE_ENHANCED_SECURITY 必须在项目级设置,以便任何现有和未来的构建目标都继承此设置。
只有在经过认真考虑并有充分理由后,才应禁用此设置。
步骤 1:增强安全性
1a. 在项目级别启用增强安全性。 执行 Enable Enhanced Security at project level 任务。其中包含两条路径:
- 项目使用项目级 xcconfig — 通过
XcodeUpdate将ENABLE_ENHANCED_SECURITY = YES写入 xcconfig。将该任务标记为已完成。 - 项目仅有 pbxproj — 任何 MCP 工具都无法直接写入项目级 pbxproj 设置,因此用户必须在 Xcode 中设置。给出以下确切步骤(每次重新展示时都逐字重复):"在 Xcode 中打开项目。在 Project Navigator 中选择项目(最顶部的条目,而不是某个 target)。前往 Build Settings,将范围切换为 All / Combined,搜索
ENABLE_ENHANCED_SECURITY,将项目级列(target 列的左侧)设置为YES。保存。" 然后使用AskUserQuestion给出两个选项:我已启用 和 再次展示步骤。选择 我已启用 后,用 Bash 验证:grep -E 'ENABLE_ENHANCED_SECURITY *= *YES' <project-root>/<ProjectName>.xcodeproj/project.pbxproj。如果找到匹配项,将该任务标记为已完成。如果没有找到,不要继续:确认很可能是在实际未做更改的情况下被接受——误按了 Enter,或者忘记保存。明确说明这一点,逐字重新展示步骤,然后再次询问。循环执行——每次确认后重新运行 grep,只要仍未找到就重新展示步骤——直到 grep 找到ENABLE_ENHANCED_SECURITY = YES。
1b. 更新增强安全性授权文件。 在阶段 4 步骤 5 中创建的细粒度 Apply Enhanced Security entitlements to <target> 任务已经列举了需要更改的 target(Partial、Off 和 No-entitlements-file 类别——Up-to-date 和 Skipped 被排除)。执行这些任务。
阅读 references/enhanced-security.md 了解完整的键列表、默认值和支持的产品类型列表。有关各个子选项的详细信息,请参阅:
references/pointer-authentication.md— arm64e 指针签名references/typed-allocators.md— 类型感知内存分配references/stack-zero-init.md— 自动栈变量清零references/readonly-platform-memory.md— dyld 状态保护references/runtime-restrictions.md— dylib 和 Mach 消息限制references/security-compiler-warnings.md— 安全相关的编译器警告references/cpp-hardening.md— C++ 标准库加固和边界检查references/hardware-memory-tagging.md— ARM MTEreferences/checked-pointer-arithmetic.md— 受检指针算术(CPA2)
指针认证与二进制依赖。 增强安全性是一组相互独立的保护措施;只有指针认证会级联到 arm64e。始终建议在项目级别设置 ENABLE_ENHANCED_SECURITY = YES。如果项目有一个二进制 Swift Package、xcframework 或预构建 framework 不提供 arm64e,正确的缓解措施是在所有链接该依赖项的 target 上以 target 级别覆盖 ENABLE_POINTER_AUTHENTICATION = NO——而不是跳过增强安全性。在报告中列出有问题的依赖项,以便用户可以向供应商要求 arm64e 支持,并在日后解除该覆盖。
arm64e.x1 是指针认证切片,因此在指针认证关闭的情况下不应构建它。不提供 arm64e 切片的二进制依赖项很可能也不提供 arm64e.x1。在每个获得 target 级别 ENABLE_POINTER_AUTHENTICATION = NO 的 target 上,还要设置 target 级别的 ENABLE_HARDWARE_CHECKED_POINTER_ARITHMETIC_SLICE = NO。步骤 4 会跳过这些 target,因此审计不会在那里添加受检指针算术授权。如果某个 target 已经在之前的配置中带有 com.apple.security.hardened-process.checked-allocations.enforce-checked-pointer-arithmetic-overflow,请报告它——构建时会警告:在没有 arm64e.x1 的情况下它不会生效。
生产方——以库/框架为目标的通用二进制文件。 强烈建议在库和框架目标上也启用指针认证——不要因为通用二进制文件在磁盘上体积更大就跳过它(RAM 占用和执行成本不变;dyld 只加载一个切片)。启用指针认证后已经会自动构建 arm64 和 arm64e 两个切片,因此无需显式设置 ARCHS。同样的理由也适用于受检指针算术,它需要追加 arm64e.x1 切片:只有当库提供该切片时,为 arm64e.x1 构建的使用方才能在库的代码上获得受检算术——使用方 App 还必须满足其他必要条件才能在运行时强制生效。第 4 步会将该构建设置应用到这些目标。参见 references/universal-binaries-for-libraries.md 和 references/checked-pointer-arithmetic.md。
对于每个任务:
-
根据此 apply 任务的描述(从审计任务复制过来的
Category:/Missing entitlements:行)组合变更集。- 支持 Entitlements 的类别(Partial / Off / No-entitlements-file):通过
AddEntitlement添加/更新 entitlements;如果缺少.entitlements则创建它,并配置CODE_SIGN_ENTITLEMENTS。DriverKit 目标仅支持构建设置——对它们跳过 entitlement 更改。 - 库/框架类别:不做 entitlement 工作,也不做构建设置更改——指针认证已经会自动生成两个切片。唯一要做的是下面第 2 项中的分发检查。
- 支持 Entitlements 的类别(Partial / Off / No-entitlements-file):通过
-
按目标设置构建设置。
ENABLE_ENHANCED_SECURITY = YES已在项目级别设置(见上文第 1a 步),因此它会将ENABLE_POINTER_AUTHENTICATION = YES级联到每个目标。模拟器构建无需覆盖——构建系统会自动为模拟器 SDK 去掉arm64e。唯一的按目标覆盖:对于每个链接了不提供arm64e的二进制依赖的目标,在目标级别无条件设置ENABLE_POINTER_AUTHENTICATION = NO(该依赖在任何平台上都无法作为arm64e链接)。跳过已有显式目标级别值的目标(参见其Audit <target>任务中的审计表块)。对于每个指针认证最终会被启用的库/框架类别目标(该目标的平台支持 arm64e,且不存在已有的目标级别
ENABLE_POINTER_AUTHENTICATION = NO),无需更改构建设置——指针认证会自动追加arm64e切片。只需检查分发的构建是否同时生成arm64和arm64e切片:如果该目标在其 Release/分发配置中设置了ONLY_ACTIVE_ARCH = YES,则在报告中警告使用方将获得单架构产物。不要自动启用默认关闭的子选项。硬件内存标记属于第 3 步,受检指针算术属于第 4 步。
-
按目标应用变更集:使用
AddEntitlement添加或更新 entitlements(当目标没有.entitlements文件时创建它并配置CODE_SIGN_ENTITLEMENTS);并应用构建设置更改。
处理完所有目标后,报告:"已在 N 个目标上启用 Enhanced Security。在 T 个链接了不含 arm64e 的二进制依赖的目标上添加了目标级别的 ENABLE_POINTER_AUTHENTICATION = NO。在 U 个库/框架目标上生成通用 arm64/arm64e 二进制文件。" 如果项目是仅含 pbxproj 且 Verify Enhanced Security at project level 成功,则追加:"Enhanced Security 已在项目级别启用(你在 Xcode 中设置的)。" 如果用户跳过了指南步骤,则追加:"本次运行未启用项目级别的 ENABLE_ENHANCED_SECURITY——在 Xcode 中启用后重新运行该技能。"
用户已在“Phase 4”中批准了此操作——无需进一步提示。
在多目标项目上,按目标的 Apply Enhanced Security entitlements 任务占据了 Phase-5 的大部分实际耗时。每个任务都会编辑该目标的 .entitlements plist。
第 2 步:警告
如果是纯 Swift,跳过整个步骤。本步骤涵盖三组,每组都以其各自的计划子项为前提 —— 编译器警告、静态分析器警告和 Clang-tidy 警告。跳过任何子项未勾选或已删除的组。对于每一项设置,查阅该 target 的 Audit <target> 任务描述(Audit 表块),并跳过其行标记为 already hardened 的个别设置。否则,应用 target 级别的设置(参见“如何应用构建设置”)。
编译器警告(每次构建都会触发):
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR—— 非 void 函数在没有返回值的情况下返回属于未定义行为;调用方会读取返回寄存器中碰巧存在的任何内容。将其提升为错误可在编译时捕获此问题。YES_ERROR是 Xcode 文档中记载的“将此特定警告视为错误”的值 —— 它不会把所有警告都变成错误。GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE—— 读取未初始化的栈值会泄露先前栈帧的内容,并让攻击者利用残留数据控制执行流。激进模式会对更多情况发出警告(例如条件初始化路径)。CLANG_WARN_IMPLICIT_FALLTHROUGH = YES—— 隐式switch贯穿是分支错误最常见的来源之一;该警告会在有意为之的情况下强制使用显式的[[fallthrough]]/__attribute__((fallthrough))。GCC_WARN_64_TO_32_BIT_CONVERSION = YES—— 将size_t/指针静默窄化为int是整数截断漏洞的典型来源(长度检查在宽值上通过,随后在窄值上失败放行)。GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES(仅 C/ObjC)—— 隐式声明已在 C99 中移除,在现代 C 中会产生错误的调用约定和错误的返回类型假设。始终视为错误。
这两个 YES_ERROR / … ERRORS = YES 设置是有作用范围的:它们只将其自身特定的警告提升为错误,而非项目中的所有警告。
静态分析器警告(在 Build and analyze 期间运行,而非常规构建):
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES—— 浮点循环计数器可能因舍入而停滞或超出预期;分析器会标记可能因此成为安全相关缺陷的循环。CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES——rand()/random()是可预测的伪随机数生成器,不适合任何安全用途;分析器会标记其使用,以便调用方改用arc4random_uniform或SecRandomCopyBytes。CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES—— 标记strcpy、strcat及其同类函数,它们本质上不安全;调用方应改用有长度限制的变体(strlcpy、strlcat、snprintf)。
Clang-tidy 警告(clang-tidy 集成检查,属于 clang 静态分析器的一部分;它们仅在 Build and analyze / clang --analyze 期间触发,从不在常规构建中触发,因此没有破坏构建的风险,采用者也无需额外安装任何东西):
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES—— 标记与外围条件重复的分支条件,这通常是复制粘贴或逻辑错误的迹象。
按组简要报告,例如:“已启用编译器警告、静态分析器警告和 clang-tidy 警告。” —— 仅列出实际应用的组。
第 3 步:硬件内存标记
如果 硬件内存标记 子项(位于“增强安全性”下)未被勾选或已被删除,请跳过此步骤。
硬件内存标记仅支持 SUPPORTED_PLATFORMS(或 SDKROOT)为 macosx、iphoneos / iphonesimulator、watchos 或 xros / xrsimulator 的目标。
硬件支持需要搭载 A19 芯片或更新芯片的 iPhone 或 iPad、搭载 M5 芯片或更新芯片的 Mac 或 Apple Vision Pro,或搭载 S11 芯片或更新芯片的 Apple Watch。
阅读 references/hardware-memory-tagging.md,并对每个受支持的目标应用这两个键:com.apple.security.hardened-process.checked-allocations,以及其用于非致命发布的 soft-mode 子选项。仅软模式本身不起作用——它修改父键而非替换它。用户已在“第 4 阶段”中批准此项——无需进一步提示。
第 4 步:受检指针运算
在 Step 1 和 Step 3 中运行的步骤之后运行此步骤:它会读取 Step 1 可能更改的设置以及 Step 3 可能添加的授权。受检指针运算需要 arm64e.x1 切片,而此步骤仅在已构建带指针认证的 arm64e 切片的目标上启用该切片。运行时强制还要求同一目标上启用硬件内存标记。
如果 受检指针运算 子项未被勾选或已被删除,请跳过此步骤。
应用于每个 Checked pointer arithmetic: 行内容为 eligible-entitlement 或 eligible-slice-only 的目标;跳过其余目标。该行在第 3 阶段第 4 步中计算,是唯一的资格测试——不要在此处重新推导。
然后按目标检查以下条件,并重新读取每个值:Step 1 可能已更改构建设置,Step 3 可能已添加授权。当目标所受的任一条件不满足时,跳过该目标并报告。
ENABLE_ENHANCED_SECURITY求值为YES—— 仅限eligible-entitlement目标,因为该授权需要此能力。ENABLE_POINTER_AUTHENTICATION求值为YES—— 两种目标均适用,因为arm64e.x1是指针认证切片。- 授权文件中存在
com.apple.security.hardened-process.checked-allocations—— 仅限eligible-entitlement目标,因为运行时强制依赖硬件内存标记。当 Step 3 未运行、跳过此目标,或 硬件内存标记 子项未被勾选时,该键不存在。
运行时强制需要运行 iOS 且搭载 A20 Pro 芯片或更新芯片的设备,或运行 watchOS 且搭载 S11 芯片或更新芯片的设备。
阅读 references/checked-pointer-arithmetic.md 并按目标应用。对于 eligible-entitlement 目标,应用两部分:在目标级别设置 ENABLE_HARDWARE_CHECKED_POINTER_ARITHMETIC_SLICE = YES(目标的 xcconfig,否则使用 UpdateTargetBuildSetting),并使用 AddEntitlement 添加 com.apple.security.hardened-process.checked-allocations.enforce-checked-pointer-arithmetic-overflow。两部分均为必需,因为仅切片不会强制受检指针运算,并且如果设置了授权而目标未构建 arm64e.x1,Xcode 会在构建时发出警告。对于 eligible-slice-only 目标,仅应用构建设置。
通过 TaskUpdate 在 Apply Checked Pointer Arithmetic 任务的 description 中记录每个目标的结果,每个目标一行,以便第 7 阶段(报告与决策文档)从一个位置读取:
<target>: applied | skipped: <reason>
对于从未符合资格的目标,使用 skipped: not eligible — <reason from the target's Checked pointer arithmetic: line>;对于符合资格但未通过上述重新读取的目标,使用 skipped: ENABLE_ENHANCED_SECURITY is <value>、skipped: ENABLE_POINTER_AUTHENTICATION is <value> 或 skipped: no hardware memory tagging entitlement。用户已在“第 4 阶段”中批准此项——无需进一步提示。
第 5 步:其他诊断设置
如果 Additional diagnostic settings 计划项未被勾选或已被删除,则跳过此步骤。
阅读 references/additional-settings.md 并按照其中的说明操作。用户已在“第 4 阶段”批准此项——无需再次询问。
第 6 步:边界安全采纳
如果 Bounds safety adoption 计划项未被勾选或已被删除,则跳过此步骤。
此步骤不会应用任何更改——它仅输出指引。
对于 C 项目(根据第 3 阶段第 2 步检测到存在 C),打印:
“要采纳
ENABLE_C_BOUNDS_SAFETY(基于注解的 C 边界安全),请调用adopt-c-bounds-safety技能。”
对于 C++ 项目(根据第 3 阶段第 2 步检测到存在 C++ 或 Objective-C++——包括对其他扩展名文件上的任何 sourcecode.cpp.* 覆盖),打印:
“要采纳
ENABLE_CPLUSPLUS_BOUNDS_SAFE_BUFFERS(C++ 边界安全缓冲区模式),请阅读 https://clang.llvm.org/docs/SafeBuffers.html 上的文档”
第 6 阶段:询问已禁用的设置
如果 Inquire about disabled settings 计划项未被勾选或已被删除,则跳过此阶段。
对于每个被刻意禁用但缺少书面理由的设置,此阶段会暂停并等待一次用户回复。如果候选列表很长,请提前告知数量,让用户心里有数(“我发现 7 个被刻意禁用的设置;让我逐一询问”)。
当 deliberately disabled 谓词(定义于 references/reading-build-settings.md)成立时,该行即为候选行。对 Audit <target> 任务执行 TaskList,并对每个任务执行 TaskGet;每个描述的 Deliberately-disabled: 行列出了该目标的候选行。标记无条件的 ENABLE_POINTER_AUTHENTICATION = NO,因为它会在设备构建中禁用指针认证。在 Checked pointer arithmetic: 行内容为 not-eligible: opted out 的目标上标记 ENABLE_HARDWARE_CHECKED_POINTER_ARITHMETIC_SLICE = NO——该原因意味着此选择退出是目标与 arm64e.x1 slice 之间的唯一障碍。对于其他 not-eligible 原因不要标记,因为在这些情况下该 slice 无论如何都无法构建。仅限于其 Scope(在 references/security-settings-reference.md 中)涵盖第 3 阶段第 2 步检测到的语言的设置;上述两个设置没有 Scope,因此无论语言如何都会标记。
对于每个候选设置,走查第 4 阶段第 5 步创建的对应 Inquire about <MACRO> on <target> 任务:
- 如果决策文档中有一条状态为
Disabled且带有理由的记录 → 在报告中注明并继续。 - 否则 →
AskUserQuestion:“我发现<MACRO>被显式设置为NO且没有解释。这有原因吗?”再次确认该宏是deliberately disabled,而不仅仅是 Xcode 默认的 OFF——只应指出显式覆盖。记录理由(如果没有理由,则建议重新启用)。
同样的流程也适用于 ENABLE_ENHANCED_SECURITY = NO,如果它出现在任何任务的 Deliberately-disabled: 行中。
阶段 7:报告与决策文档
生成一份简洁的总结:
- 已启用 — 项目范围内已启用的设置。
- 各目标的安全增强 — 每个目标一行:名称、最终状态(已是最新 / 已应用 / 被用户跳过)、简短的变更(添加的 entitlements、是否创建了 entitlements 文件、该目标现在构建哪些架构切片、是否应用了受检指针算术)。将被跳过的目标汇总为一行。对于受检指针算术,
TaskGet获取Apply Checked Pointer Arithmetic任务,并使用其按目标的结果行,包括每次跳过的原因。 - 已处于活动状态 — 已正确配置的设置。
- 已询问 — 发现已禁用以及询问结果的设置。
- 测试你的应用 — 给用户的行动项:在支持所有已启用加固的真实硬件(而非模拟器)上进行测试,留意保护是否触发,并修复出现的崩溃和模拟崩溃报告。只有在对加固后的应用进行充分测试后,才能发布给客户——否则它可能在生产环境中崩溃或运行缓慢。特别是对于硬件内存标记,在禁用软模式以强制执行之前,先修复软模式产生的模拟崩溃报告。受检指针算术没有软模式,内存标记的软模式也不涵盖它,因此请在发布前在支持的硬件上进行测试:潜在的指针算术 bug 会终止应用。
决策文档。 TaskGet 获取 Report and update decision document 任务以读取决策文档路径。然后读取 references/decision-document.md 并遵照它在该路径创建或更新文档。
在阶段 7 之后——以及阶段 5–7 期间的任何错误路径上——将运行此最终任务:
Prompt to remove plan file— 通过AskUserQuestion询问用户:“审计已完成。是否从你的项目中移除计划文件xcode-security-audit-plan.md?”- 是,移除它(推荐) →
XcodeRM xcode-security-audit-plan.md deleteFiles:true - 否,保留它 → 原地保留;它将留在 Project Navigator 中,作为已批准内容的记录。用户可以稍后从 Xcode 或 Finder 中删除它。
- 是,移除它(推荐) →
如果移除失败,警告用户,但不要阻止退出。
面向用户的交互准则
- 保持回复简洁。 使用短句。
- 使用完整句子表达。 不要使用短语片段。不要输出像“没有现成的决策文档。”这样的电报式名词短语——要写成完整的句子(“我没有找到现成的决策文档——我会在结尾创建一个。”)。
- 阶段编号仅供内部使用。 绝不要在面向用户的叙述中提及阶段编号或步骤编号。直接描述结果:说“我不需要询问你关于已禁用设置的问题”,而不是“不会有第 6 阶段的询问问题”。这适用于叙述、状态行以及任何 AskUserQuestion 文本。
- 不要使用技能内部术语。 不要在面向用户的叙述中使用“catalog”“audit table”之类的词——这些是技能内部的术语。用日常的 Xcode 术语描述正在发生的事情:“检查已知的安全构建设置”“目标列表”“我刚刚运行的分析”。
- 将用户提问控制在最少。 三个计划内问题:“阶段 1”结尾的简报确认提示(开始审计 / 取消)、“阶段 4”结尾的计划批准提示(运行 / 取消),以及“阶段 7”结尾的保留或删除计划文件提示。其他问题视情况而定:在“阶段 6”中询问有意禁用的设置(仅当显式的
= NO缺少文档化理由时),以及Enable Enhanced Security at project level确认提示(仅适用于仅含 pbxproj 的项目且勾选了该子项时)。 - 报告进度,以便用户能够跟踪:“正在启用……”“正在评估……”“正在保留/还原……”
- 使用
AskUserQuestion进行简报确认(开始审计 / 取消)、计划批准(运行 / 取消)、在“阶段 6”中询问已禁用设置、阶段 5 步骤 1a 中的Enable Enhanced Security at project level确认(仅含 pbxproj),以及“阶段 7”结尾的保留或删除计划文件提示。 - 提问时提供用户回答问题所需的背景信息。例如,在询问是否启用某项安全保护之前,先描述它的好处。要描述它提供的保护,而不是它如何被启用。
- 在列出 Xcode 构建设置时,使用项目符号列表。不要使用逗号分隔的列表。