copilotManagedSettings.ts ×20

Frontier kind: Code frontier

unlabeled · c_a70fdea7b310

564 tests · 4818 LOC · 24 files · introduces 0 tests · 373 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
20 ranges373 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
619 ranges4818 lines · 24 files · Browse complete extent
All tests (intent)
564 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 373 introduced LOC across 20 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/policy/common/copilotManagedSettings.ts 373 introduced LOC · 20 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- copilotManagedSettings.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Event } from '../../../base/common/event.js';
7 > import { IPolicyData } from '../../../base/common/defaultAccount.js';
8 > import { IExtraKnownMarketplaceEntry, extraKnownMarketplacesToConfigDict } from '../../../base/common/managedSettings.js';
9 > import { IManagedSettingPolicyDefinition, IManagedSettingsPolicyDefinitions, ManagedSettingValue, ManagedSettingsData } from '../../../base/common/policy.js';
10 > import { IStringDictionary } from '../../../base/common/collections.js';
11 > import { isEmptyObject, isObject, isString } from '../../../base/common/types.js';
12 > import { createDecorator } from '../../instantiation/common/instantiation.js';
13 > import { PolicyDefinition } from './policy.js';
14 >
15 > export type { ManagedSettingsData } from '../../../base/common/policy.js';
16 >
17 > export type RawManagedSettingsData = Readonly<Record<string, unknown>>;
18 >
19 > /** Windows registry root for GitHub Copilot policies. */
20 > export const GITHUB_COPILOT_WIN32_REGISTRY_PATH = 'SOFTWARE\\Policies\\GitHubCopilot';
21 >
22 > /** Windows product name passed to the native policy watcher. */
23 > export const GITHUB_COPILOT_WIN32_POLICY_NAME = 'GitHubCopilot';
24 >
25 > /** macOS CFPreferences application ID for GitHub Copilot managed preferences. */
26 > export const GITHUB_COPILOT_MACOS_BUNDLE_ID = 'com.github.copilot';
27 >
28 > /** MDM key for the V0 managed setting. */
29 > export const COPILOT_DISABLE_BYPASS_PERMISSIONS_MODE_KEY = 'permissions.disableBypassPermissionsMode';
30 >
31 > /** Managed-settings key for enterprise plugin enablement (carried as a JSON-encoded `{ [pluginId]: boolean }`). */
32 > export const COPILOT_ENABLED_PLUGINS_KEY = 'enabledPlugins';
33 >
34 > /** Managed-settings key for enterprise marketplaces (carried as a JSON-encoded `{ [name]: url-or-shorthand }`). */
35 > export const COPILOT_EXTRA_MARKETPLACES_KEY = 'extraKnownMarketplaces';
36 >
37 > /** Managed-settings key for the strict-marketplace allowlist (carried as a JSON-encoded array of source entries; absent = no restrictions, `[]` = lockdown). */
38 > export const COPILOT_STRICT_MARKETPLACES_KEY = 'strictKnownMarketplaces';
39 >
40 > /** Managed-settings key for the per-server MCP allowlist (carried as a JSON-encoded array of matcher entries; absent = no allow restriction, `[]` = only servers matching an entry, i.e. block all). */
41 > export const COPILOT_ALLOWED_MCP_SERVERS_KEY = 'allowedMcpServers';
42 >
43 > /** Managed-settings key for the per-server MCP denylist (carried as a JSON-encoded array of matcher entries; deny always takes precedence over allow). */
44 > export const COPILOT_DENIED_MCP_SERVERS_KEY = 'deniedMcpServers';
45 >
46 > /**
47 > * Managed-settings key for the default chat model (carried as a plain string: `auto`, a model
48 > * family name, or a full model id). Nested under `permissions` in the managed-settings schema
49 > * (alongside {@link COPILOT_DISABLE_BYPASS_PERMISSIONS_MODE_KEY}), so it flattens to the dot-path
50 > * `permissions.model` in the normalized bag — the key policy `value()` callbacks must read.
51 > */
52 > export const COPILOT_MODEL_KEY = 'permissions.model';
53 >
54 > /**
55 > * Enterprise OTel managed-settings keys. These are the scalar leaves of the canonical
56 > * `telemetry` block from the cross-client managed-settings schema (see the CLI
57 > * `ManagedTelemetrySettings`); they flatten to dot-path bag keys via
58 > * {@link normalizeManagedSettings}, so no {@link STRUCTURED_MANAGED_SETTINGS} entry is needed.
59 > * The `telemetry.resourceAttributes` and `telemetry.headers` map fields are structured
60 > * ({@link STRUCTURED_MANAGED_SETTINGS} rows carry them as JSON-encoded objects under their nested
61 > * keys); `telemetry.serviceName` is a scalar.
62 > */
63 >
64 > /** Managed-settings key for enterprise OTel enablement. */
65 > export const COPILOT_OTEL_ENABLED_KEY = 'telemetry.enabled';
66 >
67 > /** Managed-settings key for the enterprise OTLP collector endpoint. */
68 > export const COPILOT_OTEL_ENDPOINT_KEY = 'telemetry.endpoint';
69 >
70 > /** Managed-settings key for the enterprise OTLP protocol (`http/json`, `http/protobuf`, or `grpc`). */
71 > export const COPILOT_OTEL_PROTOCOL_KEY = 'telemetry.protocol';
72 >
73 > /** Managed-settings key for enterprise OTel content capture. */
74 > export const COPILOT_OTEL_CAPTURE_CONTENT_KEY = 'telemetry.captureContent';
75 >
76 > /** Managed-settings key that prevents users from enabling OTel content capture themselves. */
77 > export const COPILOT_OTEL_LOCK_CAPTURE_CONTENT_KEY = 'telemetry.lockCaptureContent';
78 >
79 > /** Managed-settings key for the OTel `service.name` resource attribute. */
80 > export const COPILOT_OTEL_SERVICE_NAME_KEY = 'telemetry.serviceName';
81 >
82 > /** Managed-settings key for additional OTel resource attributes (a `{ [k]: string }` map). */
83 > export const COPILOT_OTEL_RESOURCE_ATTRIBUTES_KEY = 'telemetry.resourceAttributes';
84 >
85 > /** Managed-settings key for extra OTLP exporter headers (a `{ [k]: string }` map). */
86 > export const COPILOT_OTEL_HEADERS_KEY = 'telemetry.headers';
87 >
88 > const managedSettingValueCallbacks = new Map<string, (policyData: IPolicyData) => ManagedSettingValue | undefined>();
89 >
90 > /**
91 > * Standard pass-through `value` callback for a managed-settings-driven policy: locks the setting
92 > * to the managed value when the enterprise has set it, and returns `undefined` otherwise so the
93 > * user's own setting falls through. Use for the common case; policies that combine the managed
94 > * value with other conditions (e.g. `chat_preview_features_enabled`) keep a custom callback.
95 > *
96 > * The callback is memoized per key, so repeated calls for the same key return the SAME function
97 > * reference. That reference identity is what lets `isSamePolicyDefinition` skip needless
98 > * re-registration, and memoizing makes the guarantee hold regardless of where the helper is called.
99 > */
100 > export function managedSettingValue(key: string): (policyData: IPolicyData) => ManagedSettingValue | undefined {
101 let callback = managedSettingValueCallbacks.get(key);
102 if (!callback) {
106 return callback;
107 }
109 > let managedModelValueCallback: ((policyData: IPolicyData) => ManagedSettingValue | undefined) | undefined;
110 >
111 > /**
112 > * `value` callback for the default-chat-model managed setting ({@link COPILOT_MODEL_KEY}). Like
113 > * {@link managedSettingValue} it locks the setting to the managed value and otherwise falls through
114 > * to the user's own value, but it additionally trims the string and treats a blank/whitespace-only
115 > * value as "unset" (returns `undefined`) — an admin clearing the field must not lock the setting to
116 > * an empty string. The model-specific normalization lives here, alongside the other managed-settings
117 > * handling, rather than inline at the policy declaration, so every managed-settings control is wired
118 > * the same way.
119 > *
120 > * Memoized (single key) so repeated calls return the SAME function reference, matching the
121 > * reference-identity contract {@link managedSettingValue} relies on for `isSamePolicyDefinition`.
122 > */
123 > export function managedModelValue(): (policyData: IPolicyData) => ManagedSettingValue | undefined {
124 if (!managedModelValueCallback) {
125 managedModelValueCallback = policyData => {
131 return managedModelValueCallback;
132 }
134 > export const INativeManagedSettingsService = createDecorator<INativeManagedSettingsService>('nativeManagedSettingsService');
135 >
136 > export interface INativeManagedSettingsService {
137 > readonly _serviceBrand: undefined;
138 > readonly managedSettings: ManagedSettingsData;
139 > readonly onDidChangeManagedSettings: Event<ManagedSettingsData>;
140 > updatePolicyDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): Promise<ManagedSettingsData>;
141 > }
142 >
143 > export class NullNativeManagedSettingsService implements INativeManagedSettingsService {
144 readonly _serviceBrand: undefined;
145 readonly managedSettings: ManagedSettingsData = {};
146 readonly onDidChangeManagedSettings = Event.None;
148 > async updatePolicyDefinitions(): Promise<ManagedSettingsData> { return this.managedSettings; }
149 > }
150 >
151 function flattenManagedSettings(object: unknown): Record<string, string | number | boolean> {
152 const result: Record<string, string | number | boolean> = {};
154 return result;
155 }
157 function flattenManagedSettingsValue(value: unknown, prefix: string | undefined, result: Record<string, string | number | boolean>): void {
158 if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
171 }
172 }
174 function isManagedSettingsObject(value: unknown): value is Record<string, unknown> {
175 return typeof value === 'object' && value !== null && !Array.isArray(value);
176 }
178 > /**
179 > * Aggregate the `managedSettings` declarations of every policy definition into a single
180 > * key -> definition map. This is the single source of truth for which Copilot managed-settings
181 > * keys (and their value types) are honored, and it drives both delivery channels: the native
182 > * MDM watcher and the server `managed_settings` endpoint projection.
183 > */
184 > export function collectManagedSettingsDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): IManagedSettingsPolicyDefinitions {
185 const definitions: Record<string, IManagedSettingPolicyDefinition> = {};
186 for (const policyName in policyDefinitions) {
194 return definitions;
195 }
197 > /**
198 > * Whether any policy in `policyDefinitions` declares at least one managed-settings key. Cheap
199 > * existence check (short-circuits) used to decide whether the native MDM watcher is needed at all,
200 > * without aggregating the full {@link collectManagedSettingsDefinitions} map.
201 > */
202 > export function hasManagedSettingsDefinitions(policyDefinitions: IStringDictionary<PolicyDefinition>): boolean {
203 for (const policyName in policyDefinitions) {
204 const policyManagedSettings = policyDefinitions[policyName].managedSettings;
209 return false;
210 }
212 > /**
213 > * Project a raw managed-settings bag onto the declared schema: keep only keys declared by a
214 > * policy definition whose runtime value matches the declared type. Undeclared keys and
215 > * type-mismatched values are dropped (with an optional warning). Values are validated, never
216 > * coerced, so a key declared as `string` keeps its string value untouched.
217 > *
218 > * This keeps the server endpoint and native MDM delivery aligned on the same
219 > * declaration-driven key set and value types.
220 > */
221 > export function projectManagedSettings(values: ManagedSettingsData, definitions: IManagedSettingsPolicyDefinitions, onWarn?: (msg: string) => void): ManagedSettingsData {
222 const projected: Record<string, ManagedSettingValue> = {};
223 for (const key in definitions) {
234 return projected;
235 }
237 > /**
238 > * A delivery channel that can provide managed settings. Managed settings can be delivered by more
239 > * than one channel, so this names the known sources to give policy evaluation and the Policy
240 > * Diagnostics report one shared vocabulary. Extend this union (and {@link MANAGED_SETTINGS_CHANNELS}
241 > * / {@link pickManagedSettings}) when adding a new channel.
242 > */
243 > export type ManagedSettingsChannel =
244 > /** GitHub `/copilot_internal/managed_settings` endpoint (server-delivered). */
245 > | 'server'
246 > /** Native MDM: OS registry (Windows) / managed preferences (macOS) via `@vscode/policy-watcher`. */
247 > | 'nativeMdm'
248 > /** File on a well-known disk path (`managed-settings.json`). */
249 > | 'file';
250 >
251 > /**
252 > * The source attributed to an effective managed setting (or to the overall report). A
253 > * {@link ManagedSettingsChannel} once a channel has won, or `'none'` when no channel contributes.
254 > */
255 > export type ManagedSettingsSource = ManagedSettingsChannel | 'none';
256 >
257 > /**
258 > * The delivery channels in fixed precedence order (highest first): native MDM → server-delivered →
259 > * file on disk. This single ordered list drives the per-key resolution in {@link pickManagedSettings}
260 > * and is the one place to extend when a new channel is introduced. Rationale for the order: the
261 > * server is harder to bypass than local MDM, and a local file is the most easily tampered with.
262 > */
263 > export const MANAGED_SETTINGS_CHANNELS: readonly ManagedSettingsChannel[] = ['nativeMdm', 'server', 'file'];
264 >
265 > /** A single channel's contribution to a managed-settings key, for provenance in the resolution. */
266 > export interface IManagedSettingsContribution {
267 > /** The channel that supplied this value. */
268 > readonly channel: ManagedSettingsChannel;
269 > /** The value the channel supplied for the key. */
270 > readonly value: ManagedSettingValue;
271 > }
272 >
273 > /** How a single managed-settings key was resolved across the delivery channels. */
274 > export interface IManagedSettingResolution {
275 > /** The effective (winning) value applied for the key. */
276 > readonly value: ManagedSettingValue;
277 > /** The channel whose value won (always the first {@link contributions} entry's channel). */
278 > readonly source: ManagedSettingsChannel;
279 > /** Every channel that supplied this key, in precedence order (winner first, overridden after). */
280 > readonly contributions: readonly IManagedSettingsContribution[];
281 > }
282 >
283 > /** The result of merging managed settings from every delivery channel on a per-key basis. */
284 > export interface IManagedSettingsPick {
285 > /** The effective merged bag: the winning value for each key contributed by any channel. */
286 > readonly values: ManagedSettingsData;
287 > /** Per-key provenance: how each key resolved and which channels were overridden. */
288 > readonly resolutions: ReadonlyMap<string, IManagedSettingResolution>;
289 > /** The channels that supplied at least one *winning* key, in precedence order. */
290 > readonly activeSources: readonly ManagedSettingsChannel[];
291 > }
292 >
293 > /**
294 > * Merge the managed-settings bags from every delivery channel on a **per-key** basis.
295 > *
296 > * Precedence (highest first): native MDM → server-delivered → file on disk. Unlike a single
297 > * authoritative source, the channels *are* merged key-by-key: for each key the highest-precedence
298 > * channel that supplies it wins, but a key that the higher channels never set is still filled in by
299 > * a lower channel. A value an admin locks via native MDM therefore cannot be overwritten by the
300 > * server or a file, while keys those higher channels leave unset remain available to lower ones.
301 > *
302 > * The parameter order matches the precedence so call sites read top-to-bottom. Centralizing the
303 > * resolution here (rather than inlining it at each call site) keeps policy evaluation
304 > * ({@link AccountPolicyService.getPolicyData}) and the Policy Diagnostics report from drifting apart,
305 > * and gives one obvious place to extend when a new channel is introduced. Empty or absent channels
306 > * contribute nothing.
307 > */
308 > export function pickManagedSettings(nativeMdm: ManagedSettingsData | undefined, server: ManagedSettingsData | undefined, file: ManagedSettingsData | undefined): IManagedSettingsPick {
309 const bags: Record<ManagedSettingsChannel, ManagedSettingsData | undefined> = { nativeMdm, server, file };
310
349 };
350 }
352 > // --- File-based managed settings ---
353 >
354 > /** macOS well-known path for file-based managed settings. */
355 > export const MANAGED_SETTINGS_MACOS_FILE_PATH = '/Library/Application Support/GitHubCopilot/managed-settings.json';
356 >
357 > /** Linux well-known path for file-based managed settings. */
358 > export const MANAGED_SETTINGS_LINUX_FILE_PATH = '/etc/github-copilot/managed-settings.json';
359 >
360 > /** Windows directory name under %ProgramFiles% for file-based managed settings. */
361 > export const MANAGED_SETTINGS_WINDOWS_DIR = 'GitHubCopilot';
362 >
363 > /** Managed settings file name. */
364 > export const MANAGED_SETTINGS_FILE_NAME = 'managed-settings.json';
365 >
366 > /**
367 > * Descriptor for a structured (object/array) managed setting: one carried across every delivery
368 > * channel as a canonical JSON string under a single key. This table is the single place that
369 > * knows how to turn a managed-settings schema field into that canonical value, so adding a
370 > * structured key is one row here (plus the policy declaration that reads the bag key).
371 > *
372 > * `key` is both the source field name read from the parsed input and the canonical bag key the
373 > * JSON string is stored under — for structured settings these are identical by contract (a
374 > * structured key's bag name matches the schema field exactly; only scalar settings flatten to a
375 > * differently-shaped dot-path, and those don't go through this table).
376 > */
377 > interface IStructuredManagedSetting {
378 > /** Source field name read from the parsed input, and the canonical bag key the JSON string is stored under. */
379 > readonly key: string;
380 > /**
381 > * Normalize the raw value into the canonical pre-stringify shape an admin authors via native
382 > * MDM. Return `undefined` to omit the key (absent or malformed value). Note an empty array (the
383 > * `strictKnownMarketplaces` lockdown case) is returned as-is, not omitted.
384 > */
385 > readonly encode: (value: unknown, onWarn?: (msg: string) => void) => unknown;
386 > }
387 >
388 > /**
389 > * Encode a managed-settings value into a canonical `{ [k]: string }` map: keeps string values
390 > * as-is and coerces number/boolean values to strings; drops keys with non-primitive values.
391 > * Returns `undefined` for a non-object input so the structured key is omitted.
392 > */
393 function encodeStringMap(value: unknown): Record<string, string> | undefined {
394 if (!isObject(value)) {
408 return out;
409 }
411 > /** Pass an object value through unchanged; omit the key for any non-object value. */
412 function encodeObject(value: unknown): object | undefined {
413 return isObject(value) ? value : undefined;
414 }
416 > /** Pass an array value through unchanged (including an empty array); omit the key otherwise. */
417 function encodeArray(value: unknown): unknown[] | undefined {
418 return Array.isArray(value) ? value : undefined;
419 }
421 > /**
422 > * Encode the schema's `{ [id]: { source } }` marketplace map into the canonical
423 > * `{ [name]: url-or-shorthand }` dict; drops malformed entries (with an optional warning) and omits
424 > * the key when there are none.
425 > */
426 function encodeExtraMarketplaces(value: unknown, onWarn?: (msg: string) => void): Record<string, string> | undefined {
427 return extraKnownMarketplacesToConfigDict(normalizeExtraKnownMarketplaces(value, onWarn));
428 }
430 > const STRUCTURED_MANAGED_SETTINGS: readonly IStructuredManagedSetting[] = [
431 > {
432 > key: COPILOT_ENABLED_PLUGINS_KEY,
433 > encode: encodeObject,
434 > },
435 > {
436 > key: COPILOT_STRICT_MARKETPLACES_KEY,
437 > encode: encodeArray,
438 > },
439 > {
440 > key: COPILOT_ALLOWED_MCP_SERVERS_KEY,
441 > encode: encodeArray,
442 > },
443 > {
444 > key: COPILOT_DENIED_MCP_SERVERS_KEY,
445 > encode: encodeArray,
446 > },
447 > {
448 > key: COPILOT_EXTRA_MARKETPLACES_KEY,
449 > encode: encodeExtraMarketplaces,
450 > },
451 > {
452 > // Nested under `telemetry`; carried as a JSON-encoded `{ [k]: string }` map. Non-string
453 > // primitive values are coerced to strings; non-primitive values are dropped.
454 > key: COPILOT_OTEL_RESOURCE_ATTRIBUTES_KEY,
455 > encode: encodeStringMap,
456 > },
457 > {
458 > // Nested under `telemetry`; carried as a JSON-encoded `{ [k]: string }` map of OTLP headers.
459 > key: COPILOT_OTEL_HEADERS_KEY,
460 > encode: encodeStringMap,
461 > },
462 > ];
463 >
464 > /**
465 > * Read a (possibly nested) dot-separated key from a parsed managed-settings object, e.g.
466 > * `telemetry.resourceAttributes`. Returns `undefined` if any path segment is missing or not an
467 > * object. Single-segment keys behave like a plain property read.
468 > */
469 function readNestedManagedKey(obj: Record<string, unknown>, dottedKey: string): unknown {
470 let current: unknown = obj;
477 return current;
478 }
480 > /**
481 > * Return a copy of `obj` with the (possibly nested) dot-separated key removed, cloning only the
482 > * objects along the touched path so the original (and any shared sub-objects) stay untouched. The
483 > * spread-then-`delete` shape matches a destructuring rest: it copies own enumerable keys (including
484 > * an own `__proto__`) without triggering the inherited `__proto__` setter.
485 > */
486 function withNestedManagedKeyDeleted(obj: Record<string, unknown>, dottedKey: string): Record<string, unknown> {
487 const dot = dottedKey.indexOf('.');
498 return { ...obj, [head]: withNestedManagedKeyDeleted(child as Record<string, unknown>, dottedKey.slice(dot + 1)) };
499 }
501 > /**
502 > * Normalize a parsed managed-settings object (from the server `managed_settings` API, a file on
503 > * disk, or any other source using the managed-settings schema) into the canonical
504 > * `ManagedSettingsData` bag that the policy framework consumes. This is the **single**
505 > * normalization path for all delivery channels, so downstream projection and policy `value()`
506 > * callbacks behave identically regardless of source. It does not enforce the declared
507 > * `managedSettings` schema — dropping undeclared or type-mismatched keys happens later, at
508 > * {@link projectManagedSettings}.
509 > *
510 > * - Scalar leaves (`permissions.*` and any forward-compatible scalar keys) are flattened into
511 > * dot-separated keys.
512 > * - Structured settings (declared in {@link STRUCTURED_MANAGED_SETTINGS}) are carried as canonical
513 > * JSON strings under a single key each — the same shape an admin authors via native MDM.
514 > * `PolicyConfiguration` parses the JSON back into the object-typed setting on read.
515 > * `extraKnownMarketplaces` is normalized from the schema's `{ [id]: { source } }` map to the
516 > * `{ [name]: url-or-shorthand }` dict.
517 > *
518 > * Malformed marketplace entries are dropped (with an optional warning via {@link onWarn}) rather
519 > * than throwing, so a bad enterprise settings file degrades gracefully instead of blocking startup.
520 > */
521 > export function normalizeManagedSettings(parsed: Record<string, unknown>, onWarn?: (msg: string) => void): ManagedSettingsData {
522 // Spread + delete (not for..in + assignment) so the scalar remainder keeps exact `{ ...rest }`
523 // semantics: it never triggers the inherited `__proto__` setter for a source-sent own
540 return result;
541 }
543 > /**
544 > * Normalize the schema's `{ [id]: { source } }` marketplace map into an
545 > * {@link IExtraKnownMarketplaceEntry} array, preserving the marketplace `name`,
546 > * source discriminator, and any `ref`. Malformed or off-spec entries are dropped
547 > * (with an optional warning via {@link onWarn}).
548 > */
549 function normalizeExtraKnownMarketplaces(value: unknown, onWarn?: (msg: string) => void): IExtraKnownMarketplaceEntry[] | undefined {
550 if (!isObject(value)) {
576 return entries;
577 }
579 > export const IFileManagedSettingsService = createDecorator<IFileManagedSettingsService>('fileManagedSettingsService');
580 >
581 > export interface IFileManagedSettingsService {
582 > readonly _serviceBrand: undefined;
583 > readonly rawManagedSettings: RawManagedSettingsData;
584 > readonly managedSettings: ManagedSettingsData;
585 > readonly onDidChangeRawManagedSettings: Event<RawManagedSettingsData>;
586 > readonly onDidChangeManagedSettings: Event<ManagedSettingsData>;
587 > }
588 >
589 > export class NullFileManagedSettingsService implements IFileManagedSettingsService {
590 readonly _serviceBrand: undefined;
591 readonly rawManagedSettings: RawManagedSettingsData = {};
593 readonly onDidChangeRawManagedSettings = Event.None;
594 readonly onDidChangeManagedSettings = Event.None;