mcpField
A
add-policy

add-policy

github.com/microsoft开发194.4k193 次安装今天更新
代码仓库

关于 add-policy

面向 VS Code 开发者的技能指南,说明如何添加、修改和验证配置策略,涵盖操作系统策略与账户级策略。

主要功能

  1. 01添加并注册配置策略
  2. 02接入账户级策略数据
  3. 03导出策略目录与平台文件
  4. 04覆盖扩展配置策略
  5. 05运行类型检查与策略测试

适用场景

  1. 01为配置属性新增策略字段
  2. 02评审策略注册相关改动
  3. 03为扩展设置添加企业策略

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/vscode --skill add-policy

安装后在 Claude Code 中输入/add-policy确认已加载。

附带文件github-managed-settings.mdlocal-testing.md

详细介绍

添加配置策略

管理员可以通过操作系统级机制(Windows 组策略、macOS 托管偏好设置、Linux 配置文件)或 Copilot 账户级策略数据锁定配置设置。本指南介绍完整流程。

使用场景

  • 向任何配置属性添加新的 policy: 字段
  • 修改现有策略(重命名、更改类别等)
  • 审查涉及策略注册的 PR
  • 通过 IPolicyData 添加基于账户的策略支持
  • 接入企业托管设置(原生 MDM / GitHub 服务端)——参见 github-managed-settings.md
  • 通过 policyReference 让一个策略管理多个设置
  • 在本地测试账户/托管设置策略,无需真实后端——参见 local-testing.md

架构概览

策略来源(分层,后写入者优先)
来源实现策略读取方式
操作系统级(Windows 注册表、macOS plist)NativePolicyService,通过 @vscode/policy-watcher监视 Software\Policies\Microsoft\{productName}(Windows)或包标识符偏好设置(macOS)
Linux 文件FilePolicyService读取 /etc/vscode/policy.json
账户/GitHubAccountPolicyService从 IDefaultAccountService.policyData 读取 IPolicyData,并应用 value() 函数。服务端下发的托管设置位于 policyData.managedSettings;原生 MDM(INativeManagedSettingsService)和磁盘上的文件(IFileManagedSettingsService)是独立输入,AccountPolicyService 会在 getPolicyData() 中通过 pickManagedSettings(nativeMdm, server, file) 合并它们(按键优先级为原生 MDM > 服务端 > 文件;高优先级渠道锁定的键不能被覆盖,未设置的键则会沿用低优先级渠道的值)
Copilot 托管设置(原生 MDM)NativeManagedSettingsService,通过 @vscode/policy-watcher监视 SOFTWARE\Policies\GitHubCopilot(Windows)/ com.github.copilot 偏好设置(macOS);为规范的 managedSettings 集合提供数据——参见 github-managed-settings.md
Copilot 托管设置(文件)FileManagedSettingsService在主进程中,从各操作系统对应的已知路径读取并监视 managed-settings.json,再通过 IPC 暴露给渲染进程;优先级最低的托管设置渠道——参见 github-managed-settings.md
多路复用MultiplexPolicyService在主进程中组合多个操作系统/文件策略读取器;在桌面端和 Agents 窗口渲染进程中,组合主进程的 PolicyChannelClient 与 AccountPolicyService
关键文件
文件用途
src/vs/base/common/policy.tsPolicyCategory 枚举、IPolicy 接口、IPolicyReference、ManagedSettingsData、IManagedSettingsPolicyDefinitions
src/vs/platform/policy/common/policy.tsIPolicyService、AbstractPolicyService、PolicyDefinition、toSerializablePolicyDefinition(为 IPC 移除不可克隆的 value())、getRestrictedPolicyValue
src/vs/platform/policy/common/copilotManagedSettings.tsManaged settings 键常量和已知文件路径、collectManagedSettingsDefinitions、projectManagedSettings、供所有通道共用的 normalizeManagedSettings(统一规范化器)、pickManagedSettings(按键确定通道优先级)、INativeManagedSettingsService / IFileManagedSettingsService
src/vs/platform/policy/node/nativeManagedSettingsService.ts用于 Copilot managed settings 的原生 MDM 监视器(@vscode/policy-watcher)
src/vs/platform/policy/common/fileManagedSettingsService.ts基于文件的通道:从每个操作系统的已知路径读取并监视 managed-settings.json,通过 normalizeManagedSettings 进行规范化
src/vs/platform/configuration/common/configurations.tsPolicyConfiguration — 将策略映射到配置值;将 JSON 字符串形式的 managed settings 解析回类型化值;将值应用到 policyReference 设置
src/vs/platform/configuration/common/configurationRegistry.tspolicy / policyReference 注册;getPolicyReferenceConfigurations()(名称 → 从属设置)
src/vs/workbench/services/policies/common/accountPolicyService.ts基于帐户/GitHub 的策略评估;选择并投影 managed settings(原生 MDM 优先于服务端;仅使用一个权威层)
src/vs/workbench/services/accounts/browser/managedSettings.tsadaptManagedSettings — 将服务端 managed_settings 响应规范化为标准数据集合
src/vs/workbench/services/policies/common/multiplexPolicyService.ts组合多个策略服务
src/vs/workbench/contrib/policyExport/electron-browser/policyExport.contribution.ts--export-policy-data 命令行处理程序
src/vs/base/common/defaultAccount.tsIPolicyData 接口(包括 managedSettings),用于帐户级策略字段
build/lib/policies/policyData.jsonc自动生成的策略目录,包括 referencedSettings(请勿手动编辑)
build/lib/policies/policyGenerator.ts生成 ADMX/ADML(Windows)、plist(macOS)、JSON(Linux)
build/lib/test/policyConversion.test.ts策略制品生成测试

流程

步骤 1 — 将 policy 字段添加到配置属性中

找到配置注册代码(通常位于 *.contribution.ts 文件中),并在属性架构中添加一个 policy 对象。

必填字段:

确定 minimumVersion: 始终从根目录的 package.json 中读取 version,并使用 major.minor 部分。例如,如果 package.json 中有 "version": "1.112.0",则使用 minimumVersion: '1.112'。切勿硬编码 '1.99' 之类的旧版本。

policy: {
    name: 'MyPolicyName',                          // PascalCase, unique across all policies
    category: PolicyCategory.InteractiveSession,    // From PolicyCategory enum
    minimumVersion: '1.112',                        // Use major.minor from package.json version
    localization: {
        description: {
            key: 'my.config.key',                   // NLS key for the description
            value: nls.localize('my.config.key', "Human-readable description."),
        }
    }
}

可选:用于基于帐户策略的 value 函数:

如果此策略还应能通过 Copilot 帐户策略数据(来自 IPolicyData)进行控制,请添加 value 函数:

policy: {
    name: 'MyPolicyName',
    category: PolicyCategory.InteractiveSession,
    minimumVersion: '1.112',                        // Use major.minor from package.json version
    value: (policyData) => policyData.my_field === false ? false : undefined,
    localization: { /* ... */ }
}

value 函数接收 IPolicyData(来自 src/vs/base/common/defaultAccount.ts),并应:

  • 返回一个具体值,以覆盖用户设置
  • 返回 undefined,表示不应用任何帐户级覆盖(继续采用 OS 策略或用户设置)

如果需要在 IPolicyData 中添加新字段,请将其添加到 src/vs/base/common/defaultAccount.ts 中的接口。

可选:用于枚举/字符串策略的 enumDescriptions:

重要: 如果配置属性的类型为 type: 'string' 且包含 enum 数组,则必须在 localization 块中包含 enumDescriptions,且条目数量必须与 enum 数组相同。否则,npm run export-policy-data 将失败,并显示错误:enumDescriptions must exist and have the same length as enum for policy "..."。

localization: {
    description: { key: '...', value: nls.localize('...', "...") },
    enumDescriptions: [
        { key: 'opt.none', value: nls.localize('opt.none', "No access.") },
        { key: 'opt.all', value: nls.localize('opt.all', "Full access.") },
    ]
}
步骤 2 — 确保已导入 PolicyCategory
import { PolicyCategory } from '../../../../base/common/policy.js';

PolicyCategory 枚举中的现有类别:

  • Extensions
  • IntegratedTerminal
  • InteractiveSession(用于所有聊天/Copilot 策略)
  • Telemetry
  • Update

如果需要新类别,请将其添加到 src/vs/base/common/policy.ts 中的 PolicyCategory,并添加相应的 PolicyCategoryData 本地化内容。

步骤 3 — 验证 TypeScript 编译

检查 VS Code - Build 监视任务的输出,或运行:

npm run typecheck-client
步骤 4 — 导出策略数据

重新生成自动生成的策略目录:

npm run export-policy-data

此脚本会处理转译、设置 GITHUB_TOKEN(通过 gh CLI 或 GitHub OAuth 设备流),并运行 --export-policy-data。导出命令通过 GitHub API 从发行版的 product.json 中读取扩展配置策略,并将其合并到输出中。

此操作会更新 build/lib/policies/policyData.jsonc。**切勿手动编辑此文件。**请确认新策略出现在输出中。要将更改合并到 main,你需要获得代码所有者的代码审查。

扩展提供的设置策略

扩展作者不能直接添加 policy: 字段——他们的设置定义在扩展的 package.json 中,而不是 VS Code 核心中。因此,扩展设置的策略定义在 vscode-distro 的 product.json 中,位于 extensionConfigurationPolicy 键下。

工作原理
  1. 真实来源:extensionConfigurationPolicy 映射位于 vscode-distro 的 mixin/{quality}/product.json 中(stable、insider、exploration)。
  2. 运行时:VS Code 启动时,如果使用了混入发行版的 product.json,configurationExtensionPoint.ts 会读取 extensionConfigurationPolicy,并将匹配的 policy 对象附加到扩展贡献的配置属性上。
  3. 导出/构建:--export-policy-data 命令会从 package.json 中固定的提交获取发行版的 product.json,并将扩展策略合并到输出中。请使用会自动设置身份验证的 npm run export-policy-data。
发行版格式

extensionConfigurationPolicy 中的每个条目都必须包含:

"extensionConfigurationPolicy": {
    "publisher.extension.settingName": {
        "name": "PolicyName",
        "category": "InteractiveSession",
        "minimumVersion": "1.99",
        "description": "Human-readable description."
    }
}
  • name:PascalCase 格式的策略名称,在所有策略中必须唯一
  • category:必须是有效的 PolicyCategory 枚举值(例如 InteractiveSession、Extensions)
  • minimumVersion:首次推出此策略的 VS Code 版本
  • description:面向用户的描述字符串,用于为 ADMX/ADML/macOS/Linux 策略工件生成本地化键值对
添加新的扩展策略
  1. 在 vscode-distro 中全部三个质量版本的 product.json 文件(mixin/stable/、mixin/insider/、mixin/exploration/)中的 extensionConfigurationPolicy 添加条目
  2. 更新 package.json 中的 distro 提交哈希,使其指向包含新条目的 distro 提交 — 导出命令会从固定的 distro 提交中获取扩展策略
  3. 运行 npm run export-policy-data 重新生成 policyData.jsonc(参见上文第 4 步)
  4. 在 src/vs/workbench/contrib/policyExport/test/node/extensionPolicyFixture.json 中更新测试夹具,添加新条目
测试夹具

文件 src/vs/workbench/contrib/policyExport/test/node/extensionPolicyFixture.json 是一个测试夹具,必须与已签入的 policyData.jsonc 中的扩展策略保持同步。当 distro 中的扩展策略添加或更改时,必须相应更新此夹具,否则集成测试会失败,因为测试输出(根据夹具生成)将与已签入的文件(根据真实 distro 生成)不匹配。

下游使用方
使用方读取内容输出
policyGenerator.tspolicyData.jsoncADMX/ADML(Windows GP)、.mobileconfig(macOS)、policy.json(Linux)
vscode-website(gulpfile.policies.js)policyData.jsonccode.visualstudio.com/docs/enterprise/policies 上的企业策略参考表
vscode-docs根据网站构建生成docs/enterprise/policies.md

GitHub 预览功能

如果你的设置属于 GitHub 预览功能 — 即 Copilot/聊天功能,组织可以通过 GitHub 账户级策略将其禁用 — 你必须添加一个 value 函数,用于检查 policyData.chat_preview_features_enabled。

何时添加此标志

在以下条件全部满足时,添加 chat_preview_features_enabled 检查:

  • 此设置控制 Copilot 或聊天功能(例如,Agent 工具、钩子、MCP、自动批准)
  • 此功能处于预览或实验状态(通常标记为 'preview' 或 'experimental')
  • 组织管理员应能通过 GitHub 账户策略为其组织中的所有用户禁用此功能
工作原理

IPolicyData 上的 chat_preview_features_enabled 字段(定义于 src/vs/base/common/defaultAccount.ts)从用户的 GitHub Copilot 令牌权限信息中填充。组织管理员禁用预览功能后,chat_preview_features_enabled 会被设为 false。

模式

为策略添加一个 value 函数:当 chat_preview_features_enabled === false 时返回禁用值,否则返回 undefined(以采用用户自己的设置):

policy: {
    name: 'MyPreviewFeaturePolicy',
    category: PolicyCategory.InteractiveSession,
    minimumVersion: '1.xx', // Must match the first VS Code release that ships this policy.
    value: (policyData) => policyData.chat_preview_features_enabled === false ? false : undefined,
    localization: {
        description: {
            key: 'my.setting.description',
            value: nls.localize('my.setting.description', "Description of the setting."),
        }
    }
}

要点:

  • 始终使用 === false 进行比较,不要使用 !policyData.chat_preview_features_enabled — 此字段是可选的,undefined 表示“没有可用的策略数据”,此时不应禁用该功能。
  • 当此标志不为 false 时,返回 undefined,以避免账户级策略覆盖用户的设置。
  • 根据设置的类型返回禁用值:布尔值返回 false,其他类型则返回具有限制性的字符串/枚举值。
实际示例

请参阅 src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts 中的 chat.tools.global.autoApprove 和 chat.useHooks,了解使用此模式的现有设置。

企业托管设置(原生 MDM / GitHub 服务)

GitHub Copilot 企业管理员可以通过 managed-settings 集合锁定设置。 VS Code 从 两个渠道获取该集合:原生 MDM(Windows 注册表 / macOS plist) 和 GitHub /copilot_internal/managed_settings 端点。(外部 managed-settings-schema.json 也描述了 managed-settings.json 文件渠道,但 VS Code 不会读取此类文件。)VS Code 的这两个渠道都会汇入 IPolicyData.managedSettings(一个扁平的点路径集合),并由现有的 policy.value(policyData) 回调使用——不会新增 IPolicyService。

若要通过托管设置驱动策略,请在策略上声明 managedSettings,并在 value 中读取 policyData.managedSettings?.[KEY](实际的 ChatToolsAutoApprove 还会对 chat_preview_features_enabled === false 的情况进行 OR 运算):

// Existing policy shown verbatim; `minimumVersion: '1.99'` is its historical value —
// a NEW policy derives minimumVersion from package.json major.minor (see Step 1).
policy: {
    name: 'ChatToolsAutoApprove',
    category: PolicyCategory.InteractiveSession,
    minimumVersion: '1.99',
    value: (policyData) =>
        policyData.managedSettings?.[COPILOT_DISABLE_BYPASS_PERMISSIONS_MODE_KEY] === 'disable'
            || policyData.chat_preview_features_enabled === false ? false : undefined,
    managedSettings: {
        [COPILOT_DISABLE_BYPASS_PERMISSIONS_MODE_KEY]: { type: 'string' },
    },
    localization: { /* ... */ }
}

这是独立的模态——详细信息、权威 Schema 来源、辅助函数、接线方式和 新增键检查清单,请参阅 github-managed-settings.md。 添加或审核任何托管设置键之前,请先阅读该文档。

**本地测试:**若要在没有真实 GitHub 后端的情况下测试账户/托管设置流程,请使用模拟策略服务端——参阅 local-testing.md。

一个策略对应多个设置(policyReference)

一个策略可以控制多个设置(例如,在编辑器窗口和 Agents 窗口中同时控制某个 Agent)。 所有者声明完整的 policy: { name, … };其他设置则声明 policyReference: { name },指向所有者的策略名称。

// Owner setting (existing policy; `minimumVersion: '1.126'` is its historical value —
// a NEW policy uses package.json major.minor, see Step 1)
policy: { name: 'Codex3PIntegration', category: PolicyCategory.InteractiveSession, minimumVersion: '1.126', /* ... */ }

// Subordinate setting (no type/value/localization of its own)
policyReference: { name: 'Codex3PIntegration' }

policyReference 并非托管设置专用:当一个企业策略需要将多个设置锁定为相同值时,都可以使用它。该引用是一个纯指针。它本身不提供类型、value、managedSettings、restrictedValue 或本地化内容;所有者仍是策略元数据和运行时行为的唯一事实来源。

关键规则和内部机制:

  • 设置不得同时声明 policy 和 policyReference(在配置注册期间会被拒绝)。
  • 一个策略名称只能由一个设置通过 policy 拥有;其他设置通过 policyReference 关联。
  • 引用设置的类型必须与所有者的类型一致;npm run export-policy-data 会强制执行此要求,因为同一个解析后的策略值会原样应用于所有者及其引用项。
  • ConfigurationRegistry.getPolicyReferenceConfigurations() 会跟踪 policyName → Set<settingKey>;PolicyConfiguration 会在策略值变化时更新所有者设置及所有已注册的引用项。
  • AbstractPolicyService.serialize() 使用 toSerializablePolicyDefinition(),在通过 IPC 发送策略定义前,剔除无法克隆的 value() 回调。
  • AbstractPolicyService.updatePolicyDefinitions() 会按策略名称替换定义,因此较晚注册的所有者会取代较早的引用回退项;如果所有者被移除,引用项仍可提供仅包含类型的回退项。
  • 导出的策略数据包含导出期间已注册引用项的 referencedSettings;Developer: Policy Diagnostics 会在同一策略名称下列出已注册的所有者/引用设置。

关于将 policyReference 与 Copilot 托管设置结合使用的示例,请参阅 github-managed-settings.md。

示例

在代码库中搜索 policy:,即可找到不同策略配置的所有示例。

经验总结

  • 切勿手动编辑 build/lib/policies/policyData.jsonc(其文件头明确禁止这样做)。如果 npm run export-policy-data 运行失败,请修复脚本,而不是修改 JSON。常见原因:在错误的工作目录中运行(例如在主仓库而不是工作树中),导致导出时静默地使用了错误的源代码树。
  • 请在干净的环境中重新生成 policyData.jsonc,否则 PolicyExport 集成测试会在 CI 中失败。 referencedSettings 仅会记录导出时已加载的引用。直接运行 npm run export-policy-data 会加载你的开发配置文件扩展(例如 Copilot 扩展),从而将 referencedSettings 注入核心策略;而测试基于夹具进行导出(干净配置文件,不含用户扩展),不会产生这些内容,因此检入的文件会包含多余的 referencedSettings,导致 CI 失败。此问题无法在本地复现,因为测试会重复使用你的默认扩展目录。请按测试的导出方式重新生成:DISTRO_PRODUCT_JSON=<extensionPolicyFixture.json> ./scripts/code.sh --export-policy-data="$PWD/build/lib/policies/policyData.jsonc" --user-data-dir="$(mktemp -d)" --extensions-dir="$(mktemp -d)"(并设置 VSCODE_SKIP_PRELAUNCH=1)。
  • 应记录行为和业务逻辑预期,而不是照搬实现。将内部代码(例如 getPolicyData() 的合并逻辑)复制到技能文档中,一旦源代码更改,内容就会过时,且并未提供源代码之外的信息。请用文字说明约定(例如“原生 MDM 管理的设置优先于服务器下发的渠道;这两层绝不会合并”),并指向实现所在的源代码。代码块应留给面向作者的 API 约定,说明贡献者必须遵循的内容——如何声明 policy / managedSettings / value 回调,而不是重复说明运行时的内部流程。

评论

支持 Markdown