From 0ea6a23376dd7d0d55fd97e77b1bb7b2b4a019db Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 21 Oct 2025 17:08:32 -0700 Subject: [PATCH] Modularize the policy generation script (#272332) --- build/lib/policies/basePolicy.js | 57 ++ build/lib/policies/basePolicy.ts | 62 ++ build/lib/policies/booleanPolicy.js | 49 ++ build/lib/policies/booleanPolicy.ts | 61 ++ build/lib/policies/numberPolicy.js | 53 ++ build/lib/policies/numberPolicy.ts | 65 ++ build/lib/policies/objectPolicy.js | 46 + build/lib/policies/objectPolicy.ts | 58 ++ build/lib/policies/policyGenerator.js | 562 +----------- build/lib/policies/policyGenerator.ts | 696 +-------------- build/lib/policies/render.js | 271 ++++++ build/lib/policies/render.ts | 295 +++++++ build/lib/policies/stringEnumPolicy.js | 71 ++ build/lib/policies/stringEnumPolicy.ts | 92 ++ build/lib/policies/stringPolicy.js | 45 + build/lib/policies/stringPolicy.ts | 57 ++ build/lib/policies/types.js | 27 + build/lib/policies/types.ts | 65 ++ build/lib/test/booleanPolicy.test.js | 120 +++ build/lib/test/booleanPolicy.test.ts | 158 ++++ .../com.visualstudio.code.oss.mobileconfig | 61 ++ .../en-us/com.visualstudio.code.oss.plist | 274 ++++++ .../fr-fr/com.visualstudio.code.oss.plist | 274 ++++++ .../test/fixtures/policies/win32/CodeOSS.admx | 136 +++ .../policies/win32/en-us/CodeOSS.adml | 71 ++ .../policies/win32/fr-fr/CodeOSS.adml | 71 ++ build/lib/test/numberPolicy.test.js | 119 +++ build/lib/test/numberPolicy.test.ts | 157 ++++ build/lib/test/objectPolicy.test.js | 118 +++ build/lib/test/objectPolicy.test.ts | 156 ++++ build/lib/test/policyConversion.test.js | 455 ++++++++++ build/lib/test/policyConversion.test.ts | 495 +++++++++++ build/lib/test/render.test.js | 683 +++++++++++++++ build/lib/test/render.test.ts | 827 ++++++++++++++++++ build/lib/test/stringEnumPolicy.test.js | 136 +++ build/lib/test/stringEnumPolicy.test.ts | 174 ++++ build/lib/test/stringPolicy.test.js | 119 +++ build/lib/test/stringPolicy.test.ts | 157 ++++ build/package.json | 3 +- 39 files changed, 6165 insertions(+), 1231 deletions(-) create mode 100644 build/lib/policies/basePolicy.js create mode 100644 build/lib/policies/basePolicy.ts create mode 100644 build/lib/policies/booleanPolicy.js create mode 100644 build/lib/policies/booleanPolicy.ts create mode 100644 build/lib/policies/numberPolicy.js create mode 100644 build/lib/policies/numberPolicy.ts create mode 100644 build/lib/policies/objectPolicy.js create mode 100644 build/lib/policies/objectPolicy.ts create mode 100644 build/lib/policies/render.js create mode 100644 build/lib/policies/render.ts create mode 100644 build/lib/policies/stringEnumPolicy.js create mode 100644 build/lib/policies/stringEnumPolicy.ts create mode 100644 build/lib/policies/stringPolicy.js create mode 100644 build/lib/policies/stringPolicy.ts create mode 100644 build/lib/policies/types.js create mode 100644 build/lib/policies/types.ts create mode 100644 build/lib/test/booleanPolicy.test.js create mode 100644 build/lib/test/booleanPolicy.test.ts create mode 100644 build/lib/test/fixtures/policies/darwin/com.visualstudio.code.oss.mobileconfig create mode 100644 build/lib/test/fixtures/policies/darwin/en-us/com.visualstudio.code.oss.plist create mode 100644 build/lib/test/fixtures/policies/darwin/fr-fr/com.visualstudio.code.oss.plist create mode 100644 build/lib/test/fixtures/policies/win32/CodeOSS.admx create mode 100644 build/lib/test/fixtures/policies/win32/en-us/CodeOSS.adml create mode 100644 build/lib/test/fixtures/policies/win32/fr-fr/CodeOSS.adml create mode 100644 build/lib/test/numberPolicy.test.js create mode 100644 build/lib/test/numberPolicy.test.ts create mode 100644 build/lib/test/objectPolicy.test.js create mode 100644 build/lib/test/objectPolicy.test.ts create mode 100644 build/lib/test/policyConversion.test.js create mode 100644 build/lib/test/policyConversion.test.ts create mode 100644 build/lib/test/render.test.js create mode 100644 build/lib/test/render.test.ts create mode 100644 build/lib/test/stringEnumPolicy.test.js create mode 100644 build/lib/test/stringEnumPolicy.test.ts create mode 100644 build/lib/test/stringPolicy.test.js create mode 100644 build/lib/test/stringPolicy.test.ts diff --git a/build/lib/policies/basePolicy.js b/build/lib/policies/basePolicy.js new file mode 100644 index 00000000000..844b395a088 --- /dev/null +++ b/build/lib/policies/basePolicy.js @@ -0,0 +1,57 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BasePolicy = void 0; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const render_1 = require("./render"); +class BasePolicy { + type; + name; + category; + minimumVersion; + description; + moduleName; + constructor(type, name, category, minimumVersion, description, moduleName) { + this.type = type; + this.name = name; + this.category = category; + this.minimumVersion = minimumVersion; + this.description = description; + this.moduleName = moduleName; + } + renderADMLString(nlsString, translations) { + return (0, render_1.renderADMLString)(this.name, this.moduleName, nlsString, translations); + } + renderADMX(regKey) { + return [ + ``, + ` `, + ` `, + ` `, + ...this.renderADMXElements(), + ` `, + `` + ]; + } + renderADMLStrings(translations) { + return [ + `${this.name}`, + this.renderADMLString(this.description, translations) + ]; + } + renderADMLPresentation() { + return `${this.renderADMLPresentationContents()}`; + } + renderProfile() { + return [`${this.name}`, this.renderProfileValue()]; + } + renderProfileManifest(translations) { + return ` +${this.renderProfileManifestValue(translations)} +`; + } +} +exports.BasePolicy = BasePolicy; +//# sourceMappingURL=basePolicy.js.map \ No newline at end of file diff --git a/build/lib/policies/basePolicy.ts b/build/lib/policies/basePolicy.ts new file mode 100644 index 00000000000..064467f7485 --- /dev/null +++ b/build/lib/policies/basePolicy.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { renderADMLString } from './render'; +import { Category, LanguageTranslations, NlsString, Policy, PolicyType } from './types'; + +export abstract class BasePolicy implements Policy { + constructor( + readonly type: PolicyType, + readonly name: string, + readonly category: Category, + readonly minimumVersion: string, + protected description: NlsString, + protected moduleName: string, + ) { } + + protected renderADMLString(nlsString: NlsString, translations?: LanguageTranslations): string { + return renderADMLString(this.name, this.moduleName, nlsString, translations); + } + + renderADMX(regKey: string) { + return [ + ``, + ` `, + ` `, + ` `, + ...this.renderADMXElements(), + ` `, + `` + ]; + } + + protected abstract renderADMXElements(): string[]; + + renderADMLStrings(translations?: LanguageTranslations) { + return [ + `${this.name}`, + this.renderADMLString(this.description, translations) + ]; + } + + renderADMLPresentation(): string { + return `${this.renderADMLPresentationContents()}`; + } + + protected abstract renderADMLPresentationContents(): string; + + renderProfile() { + return [`${this.name}`, this.renderProfileValue()]; + } + + renderProfileManifest(translations?: LanguageTranslations): string { + return ` +${this.renderProfileManifestValue(translations)} +`; + } + + abstract renderProfileValue(): string; + abstract renderProfileManifestValue(translations?: LanguageTranslations): string; +} diff --git a/build/lib/policies/booleanPolicy.js b/build/lib/policies/booleanPolicy.js new file mode 100644 index 00000000000..1ec18d003ec --- /dev/null +++ b/build/lib/policies/booleanPolicy.js @@ -0,0 +1,49 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BooleanPolicy = void 0; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const basePolicy_1 = require("./basePolicy"); +const render_1 = require("./render"); +const types_1 = require("./types"); +class BooleanPolicy extends basePolicy_1.BasePolicy { + static from(category, policy) { + const { name, minimumVersion, localization, type } = policy; + if (type !== 'boolean') { + return undefined; + } + return new BooleanPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); + } + constructor(name, category, minimumVersion, description, moduleName) { + super(types_1.PolicyType.Boolean, name, category, minimumVersion, description, moduleName); + } + renderADMXElements() { + return [ + ``, + ` `, + `` + ]; + } + renderADMLPresentationContents() { + return `${this.name}`; + } + renderProfileValue() { + return ``; + } + renderProfileManifestValue(translations) { + return `pfm_default + +pfm_description +${(0, render_1.renderProfileString)(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +boolean`; + } +} +exports.BooleanPolicy = BooleanPolicy; +//# sourceMappingURL=booleanPolicy.js.map \ No newline at end of file diff --git a/build/lib/policies/booleanPolicy.ts b/build/lib/policies/booleanPolicy.ts new file mode 100644 index 00000000000..b37bb1e1816 --- /dev/null +++ b/build/lib/policies/booleanPolicy.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BasePolicy } from './basePolicy'; +import { CategoryDto, PolicyDto } from './policyDto'; +import { renderProfileString } from './render'; +import { Category, NlsString, PolicyType, LanguageTranslations } from './types'; + +export class BooleanPolicy extends BasePolicy { + + static from(category: CategoryDto, policy: PolicyDto): BooleanPolicy | undefined { + const { name, minimumVersion, localization, type } = policy; + + if (type !== 'boolean') { + return undefined; + } + + return new BooleanPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); + } + + private constructor( + name: string, + category: Category, + minimumVersion: string, + description: NlsString, + moduleName: string, + ) { + super(PolicyType.Boolean, name, category, minimumVersion, description, moduleName); + } + + protected renderADMXElements(): string[] { + return [ + ``, + ` `, + `` + ]; + } + + renderADMLPresentationContents() { + return `${this.name}`; + } + + renderProfileValue(): string { + return ``; + } + + renderProfileManifestValue(translations?: LanguageTranslations): string { + return `pfm_default + +pfm_description +${renderProfileString(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +boolean`; + } +} diff --git a/build/lib/policies/numberPolicy.js b/build/lib/policies/numberPolicy.js new file mode 100644 index 00000000000..4cdc03ef738 --- /dev/null +++ b/build/lib/policies/numberPolicy.js @@ -0,0 +1,53 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NumberPolicy = void 0; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const basePolicy_1 = require("./basePolicy"); +const render_1 = require("./render"); +const types_1 = require("./types"); +class NumberPolicy extends basePolicy_1.BasePolicy { + defaultValue; + static from(category, policy) { + const { type, default: defaultValue, name, minimumVersion, localization } = policy; + if (type !== 'number') { + return undefined; + } + if (typeof defaultValue !== 'number') { + throw new Error(`Missing required 'default' property.`); + } + return new NumberPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, '', defaultValue); + } + constructor(name, category, minimumVersion, description, moduleName, defaultValue) { + super(types_1.PolicyType.Number, name, category, minimumVersion, description, moduleName); + this.defaultValue = defaultValue; + } + renderADMXElements() { + return [ + `` + // `` + ]; + } + renderADMLPresentationContents() { + return `${this.name}`; + } + renderProfileValue() { + return `${this.defaultValue}`; + } + renderProfileManifestValue(translations) { + return `pfm_default +${this.defaultValue} +pfm_description +${(0, render_1.renderProfileString)(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +integer`; + } +} +exports.NumberPolicy = NumberPolicy; +//# sourceMappingURL=numberPolicy.js.map \ No newline at end of file diff --git a/build/lib/policies/numberPolicy.ts b/build/lib/policies/numberPolicy.ts new file mode 100644 index 00000000000..9bbbbddc07e --- /dev/null +++ b/build/lib/policies/numberPolicy.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BasePolicy } from './basePolicy'; +import { CategoryDto, PolicyDto } from './policyDto'; +import { renderProfileString } from './render'; +import { Category, NlsString, PolicyType, LanguageTranslations } from './types'; + +export class NumberPolicy extends BasePolicy { + + static from(category: CategoryDto, policy: PolicyDto): NumberPolicy | undefined { + const { type, default: defaultValue, name, minimumVersion, localization } = policy; + + if (type !== 'number') { + return undefined; + } + + if (typeof defaultValue !== 'number') { + throw new Error(`Missing required 'default' property.`); + } + + return new NumberPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, '', defaultValue); + } + + private constructor( + name: string, + category: Category, + minimumVersion: string, + description: NlsString, + moduleName: string, + protected readonly defaultValue: number, + ) { + super(PolicyType.Number, name, category, minimumVersion, description, moduleName); + } + + protected renderADMXElements(): string[] { + return [ + `` + // `` + ]; + } + + renderADMLPresentationContents() { + return `${this.name}`; + } + + renderProfileValue() { + return `${this.defaultValue}`; + } + + renderProfileManifestValue(translations?: LanguageTranslations) { + return `pfm_default +${this.defaultValue} +pfm_description +${renderProfileString(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +integer`; + } +} diff --git a/build/lib/policies/objectPolicy.js b/build/lib/policies/objectPolicy.js new file mode 100644 index 00000000000..ab15ce9ec3e --- /dev/null +++ b/build/lib/policies/objectPolicy.js @@ -0,0 +1,46 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ObjectPolicy = void 0; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const basePolicy_1 = require("./basePolicy"); +const render_1 = require("./render"); +const types_1 = require("./types"); +class ObjectPolicy extends basePolicy_1.BasePolicy { + static from(category, policy) { + const { type, name, minimumVersion, localization } = policy; + if (type !== 'object' && type !== 'array') { + return undefined; + } + return new ObjectPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); + } + constructor(name, category, minimumVersion, description, moduleName) { + super(types_1.PolicyType.Object, name, category, minimumVersion, description, moduleName); + } + renderADMXElements() { + return [``]; + } + renderADMLPresentationContents() { + return ``; + } + renderProfileValue() { + return ``; + } + renderProfileManifestValue(translations) { + return `pfm_default + +pfm_description +${(0, render_1.renderProfileString)(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +string +`; + } +} +exports.ObjectPolicy = ObjectPolicy; +//# sourceMappingURL=objectPolicy.js.map \ No newline at end of file diff --git a/build/lib/policies/objectPolicy.ts b/build/lib/policies/objectPolicy.ts new file mode 100644 index 00000000000..8e555133f38 --- /dev/null +++ b/build/lib/policies/objectPolicy.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BasePolicy } from './basePolicy'; +import { CategoryDto, PolicyDto } from './policyDto'; +import { renderProfileString } from './render'; +import { Category, NlsString, PolicyType, LanguageTranslations } from './types'; + +export class ObjectPolicy extends BasePolicy { + + static from(category: CategoryDto, policy: PolicyDto): ObjectPolicy | undefined { + const { type, name, minimumVersion, localization } = policy; + + if (type !== 'object' && type !== 'array') { + return undefined; + } + + return new ObjectPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); + } + + private constructor( + name: string, + category: Category, + minimumVersion: string, + description: NlsString, + moduleName: string, + ) { + super(PolicyType.Object, name, category, minimumVersion, description, moduleName); + } + + protected renderADMXElements(): string[] { + return [``]; + } + + renderADMLPresentationContents() { + return ``; + } + + renderProfileValue(): string { + return ``; + } + + renderProfileManifestValue(translations?: LanguageTranslations): string { + return `pfm_default + +pfm_description +${renderProfileString(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +string +`; + } +} diff --git a/build/lib/policies/policyGenerator.js b/build/lib/policies/policyGenerator.js index 7ddb6956c18..e9f97b49092 100644 --- a/build/lib/policies/policyGenerator.js +++ b/build/lib/policies/policyGenerator.js @@ -44,543 +44,15 @@ const minimist_1 = __importDefault(require("minimist")); const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); const JSONC = __importStar(require("jsonc-parser")); +const booleanPolicy_1 = require("./booleanPolicy"); +const numberPolicy_1 = require("./numberPolicy"); +const objectPolicy_1 = require("./objectPolicy"); +const stringEnumPolicy_1 = require("./stringEnumPolicy"); +const stringPolicy_1 = require("./stringPolicy"); +const types_1 = require("./types"); +const render_1 = require("./render"); const product = require('../../../product.json'); const packageJson = require('../../../package.json'); -var PolicyType; -(function (PolicyType) { - PolicyType["Boolean"] = "boolean"; - PolicyType["Number"] = "number"; - PolicyType["Object"] = "object"; - PolicyType["String"] = "string"; - PolicyType["StringEnum"] = "stringEnum"; -})(PolicyType || (PolicyType = {})); -function renderADMLString(prefix, moduleName, nlsString, translations) { - let value; - if (translations) { - const moduleTranslations = translations[moduleName]; - if (moduleTranslations) { - value = moduleTranslations[nlsString.nlsKey]; - } - } - if (!value) { - value = nlsString.value; - } - return `${value}`; -} -function renderProfileString(_prefix, moduleName, nlsString, translations) { - let value; - if (translations) { - const moduleTranslations = translations[moduleName]; - if (moduleTranslations) { - value = moduleTranslations[nlsString.nlsKey]; - } - } - if (!value) { - value = nlsString.value; - } - return value; -} -class BasePolicy { - type; - name; - category; - minimumVersion; - description; - moduleName; - constructor(type, name, category, minimumVersion, description, moduleName) { - this.type = type; - this.name = name; - this.category = category; - this.minimumVersion = minimumVersion; - this.description = description; - this.moduleName = moduleName; - } - renderADMLString(nlsString, translations) { - return renderADMLString(this.name, this.moduleName, nlsString, translations); - } - renderADMX(regKey) { - return [ - ``, - ` `, - ` `, - ` `, - ...this.renderADMXElements(), - ` `, - `` - ]; - } - renderADMLStrings(translations) { - return [ - `${this.name}`, - this.renderADMLString(this.description, translations) - ]; - } - renderADMLPresentation() { - return `${this.renderADMLPresentationContents()}`; - } - renderProfile() { - return [`${this.name}`, this.renderProfileValue()]; - } - renderProfileManifest(translations) { - return ` -${this.renderProfileManifestValue(translations)} -`; - } -} -class BooleanPolicy extends BasePolicy { - static from(category, policy) { - const { name, minimumVersion, localization, type } = policy; - if (type !== 'boolean') { - return undefined; - } - return new BooleanPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); - } - constructor(name, category, minimumVersion, description, moduleName) { - super(PolicyType.Boolean, name, category, minimumVersion, description, moduleName); - } - renderADMXElements() { - return [ - ``, - ` `, - `` - ]; - } - renderADMLPresentationContents() { - return `${this.name}`; - } - renderProfileValue() { - return ``; - } - renderProfileManifestValue(translations) { - return `pfm_default - -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -boolean`; - } -} -class NumberPolicy extends BasePolicy { - defaultValue; - static from(category, policy) { - const { type, default: defaultValue, name, minimumVersion, localization } = policy; - if (type !== 'number') { - return undefined; - } - if (typeof defaultValue !== 'number') { - throw new Error(`Missing required 'default' property.`); - } - return new NumberPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, '', defaultValue); - } - constructor(name, category, minimumVersion, description, moduleName, defaultValue) { - super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); - this.defaultValue = defaultValue; - } - renderADMXElements() { - return [ - `` - // `` - ]; - } - renderADMLPresentationContents() { - return `${this.name}`; - } - renderProfileValue() { - return `${this.defaultValue}`; - } - renderProfileManifestValue(translations) { - return `pfm_default -${this.defaultValue} -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -integer`; - } -} -class StringPolicy extends BasePolicy { - static from(category, policy) { - const { type, name, minimumVersion, localization } = policy; - if (type !== 'string') { - return undefined; - } - return new StringPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); - } - constructor(name, category, minimumVersion, description, moduleName) { - super(PolicyType.String, name, category, minimumVersion, description, moduleName); - } - renderADMXElements() { - return [``]; - } - renderADMLPresentationContents() { - return ``; - } - renderProfileValue() { - return ``; - } - renderProfileManifestValue(translations) { - return `pfm_default - -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -string`; - } -} -class ObjectPolicy extends BasePolicy { - static from(category, policy) { - const { type, name, minimumVersion, localization } = policy; - if (type !== 'object' && type !== 'array') { - return undefined; - } - return new ObjectPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); - } - constructor(name, category, minimumVersion, description, moduleName) { - super(PolicyType.Object, name, category, minimumVersion, description, moduleName); - } - renderADMXElements() { - return [``]; - } - renderADMLPresentationContents() { - return ``; - } - renderProfileValue() { - return ``; - } - renderProfileManifestValue(translations) { - return `pfm_default - -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -string -`; - } -} -class StringEnumPolicy extends BasePolicy { - enum_; - enumDescriptions; - static from(category, policy) { - const { type, name, minimumVersion, enum: enumValue, localization } = policy; - if (type !== 'string') { - return undefined; - } - const enum_ = enumValue; - if (!enum_) { - return undefined; - } - if (!localization.enumDescriptions || !Array.isArray(localization.enumDescriptions) || localization.enumDescriptions.length !== enum_.length) { - throw new Error(`Invalid policy data: enumDescriptions must exist and have the same length as enum_ for policy "${name}".`); - } - const enumDescriptions = localization.enumDescriptions.map((e) => ({ nlsKey: e.key, value: e.value })); - return new StringEnumPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, '', enum_, enumDescriptions); - } - constructor(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions) { - super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); - this.enum_ = enum_; - this.enumDescriptions = enumDescriptions; - } - renderADMXElements() { - return [ - ``, - ...this.enum_.map((value, index) => ` ${value}`), - `` - ]; - } - renderADMLStrings(translations) { - return [ - ...super.renderADMLStrings(translations), - ...this.enumDescriptions.map(e => this.renderADMLString(e, translations)) - ]; - } - renderADMLPresentationContents() { - return ``; - } - renderProfileValue() { - return `${this.enum_[0]}`; - } - renderProfileManifestValue(translations) { - return `pfm_default -${this.enum_[0]} -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -string -pfm_range_list - - ${this.enum_.map(e => `${e}`).join('\n ')} -`; - } -} -function renderADMX(regKey, versions, categories, policies) { - versions = versions.map(v => v.replace(/\./g, '_')); - return ` - - - - - - - - ${versions.map(v => ``).join(`\n `)} - - - - - ${categories.map(c => ``).join(`\n `)} - - - ${policies.map(p => p.renderADMX(regKey)).flat().join(`\n `)} - - -`; -} -function renderADML(appName, versions, categories, policies, translations) { - return ` - - - - - - ${appName} - ${versions.map(v => `${appName} >= ${v}`).join(`\n `)} - ${categories.map(c => renderADMLString('Category', c.moduleName, c.name, translations)).join(`\n `)} - ${policies.map(p => p.renderADMLStrings(translations)).flat().join(`\n `)} - - - ${policies.map(p => p.renderADMLPresentation()).join(`\n `)} - - - -`; -} -function renderProfileManifest(appName, bundleIdentifier, _versions, _categories, policies, translations) { - const requiredPayloadFields = ` - - pfm_default - Configure ${appName} - pfm_name - PayloadDescription - pfm_title - Payload Description - pfm_type - string - - - pfm_default - ${appName} - pfm_name - PayloadDisplayName - pfm_require - always - pfm_title - Payload Display Name - pfm_type - string - - - pfm_default - ${bundleIdentifier} - pfm_name - PayloadIdentifier - pfm_require - always - pfm_title - Payload Identifier - pfm_type - string - - - pfm_default - ${bundleIdentifier} - pfm_name - PayloadType - pfm_require - always - pfm_title - Payload Type - pfm_type - string - - - pfm_default - - pfm_name - PayloadUUID - pfm_require - always - pfm_title - Payload UUID - pfm_type - string - - - pfm_default - 1 - pfm_name - PayloadVersion - pfm_range_list - - 1 - - pfm_require - always - pfm_title - Payload Version - pfm_type - integer - - - pfm_default - Microsoft - pfm_name - PayloadOrganization - pfm_title - Payload Organization - pfm_type - string - `; - const profileManifestSubkeys = policies.map(policy => { - return policy.renderProfileManifest(translations); - }).join(''); - return ` - - - - pfm_app_url - https://code.visualstudio.com/ - pfm_description - ${appName} Managed Settings - pfm_documentation_url - https://code.visualstudio.com/docs/setup/enterprise - pfm_domain - ${bundleIdentifier} - pfm_format_version - 1 - pfm_interaction - combined - pfm_last_modified - ${new Date().toISOString().replace(/\.\d+Z$/, 'Z')} - pfm_platforms - - macOS - - pfm_subkeys - - ${requiredPayloadFields} - ${profileManifestSubkeys} - - pfm_title - ${appName} - pfm_unique - - pfm_version - 1 - -`; -} -function renderMacOSPolicy(policies, translations) { - const appName = product.nameLong; - const bundleIdentifier = product.darwinBundleIdentifier; - const payloadUUID = product.darwinProfilePayloadUUID; - const UUID = product.darwinProfileUUID; - const versions = [...new Set(policies.map(p => p.minimumVersion)).values()].sort(); - const categories = [...new Set(policies.map(p => p.category))]; - const policyEntries = policies.map(policy => policy.renderProfile()) - .flat() - .map(entry => `\t\t\t\t${entry}`) - .join('\n'); - return { - profile: ` - - - - PayloadContent - - - PayloadDisplayName - ${appName} - PayloadIdentifier - ${bundleIdentifier}.${UUID} - PayloadType - ${bundleIdentifier} - PayloadUUID - ${UUID} - PayloadVersion - 1 -${policyEntries} - - - PayloadDescription - This profile manages ${appName}. For more information see https://code.visualstudio.com/docs/setup/enterprise - PayloadDisplayName - ${appName} - PayloadIdentifier - ${bundleIdentifier} - PayloadOrganization - Microsoft - PayloadType - Configuration - PayloadUUID - ${payloadUUID} - PayloadVersion - 1 - TargetDeviceType - 5 - -`, - manifests: [{ languageId: 'en-us', contents: renderProfileManifest(appName, bundleIdentifier, versions, categories, policies) }, - ...translations.map(({ languageId, languageTranslations }) => ({ languageId, contents: renderProfileManifest(appName, bundleIdentifier, versions, categories, policies, languageTranslations) })) - ] - }; -} -function renderGP(policies, translations) { - const appName = product.nameLong; - const regKey = product.win32RegValueName; - const versions = [...new Set(policies.map(p => p.minimumVersion)).values()].sort(); - const categories = [...Object.values(policies.reduce((acc, p) => ({ ...acc, [p.category.name.nlsKey]: p.category }), {}))]; - return { - admx: renderADMX(regKey, versions, categories, policies), - adml: [ - { languageId: 'en-us', contents: renderADML(appName, versions, categories, policies) }, - ...translations.map(({ languageId, languageTranslations }) => ({ languageId, contents: renderADML(appName, versions, categories, policies, languageTranslations) })) - ] - }; -} -const Languages = { - 'fr': 'fr-fr', - 'it': 'it-it', - 'de': 'de-de', - 'es': 'es-es', - 'ru': 'ru-ru', - 'zh-hans': 'zh-cn', - 'zh-hant': 'zh-tw', - 'ja': 'ja-jp', - 'ko': 'ko-kr', - 'cs': 'cs-cz', - 'pt-br': 'pt-br', - 'tr': 'tr-tr', - 'pl': 'pl-pl', -}; async function getSpecificNLS(resourceUrlTemplate, languageId, version) { const resource = { publisher: 'ms-ceintl', @@ -648,11 +120,11 @@ async function getNLS(extensionGalleryServiceUrl, resourceUrlTemplate, languageI } // TODO: add more policy types const PolicyTypes = [ - BooleanPolicy, - NumberPolicy, - StringEnumPolicy, - StringPolicy, - ObjectPolicy + booleanPolicy_1.BooleanPolicy, + numberPolicy_1.NumberPolicy, + stringEnumPolicy_1.StringEnumPolicy, + stringPolicy_1.StringPolicy, + objectPolicy_1.ObjectPolicy ]; async function parsePolicies(policyDataFile) { const contents = JSONC.parse(await fs_1.promises.readFile(policyDataFile, { encoding: 'utf8' })); @@ -699,18 +171,18 @@ async function getTranslations() { return []; } const version = parseVersion(packageJson.version); - const languageIds = Object.keys(Languages); + const languageIds = Object.keys(types_1.Languages); return await Promise.all(languageIds.map(languageId => getNLS(extensionGalleryServiceUrl, resourceUrlTemplate, languageId, version) .then(languageTranslations => ({ languageId, languageTranslations })))); } async function windowsMain(policies, translations) { const root = '.build/policies/win32'; - const { admx, adml } = await renderGP(policies, translations); + const { admx, adml } = (0, render_1.renderGP)(product, policies, translations); await fs_1.promises.rm(root, { recursive: true, force: true }); await fs_1.promises.mkdir(root, { recursive: true }); await fs_1.promises.writeFile(path_1.default.join(root, `${product.win32RegValueName}.admx`), admx.replace(/\r?\n/g, '\n')); for (const { languageId, contents } of adml) { - const languagePath = path_1.default.join(root, languageId === 'en-us' ? 'en-us' : Languages[languageId]); + const languagePath = path_1.default.join(root, languageId === 'en-us' ? 'en-us' : types_1.Languages[languageId]); await fs_1.promises.mkdir(languagePath, { recursive: true }); await fs_1.promises.writeFile(path_1.default.join(languagePath, `${product.win32RegValueName}.adml`), contents.replace(/\r?\n/g, '\n')); } @@ -721,12 +193,12 @@ async function darwinMain(policies, translations) { throw new Error(`Missing required product information.`); } const root = '.build/policies/darwin'; - const { profile, manifests } = await renderMacOSPolicy(policies, translations); + const { profile, manifests } = (0, render_1.renderMacOSPolicy)(product, policies, translations); await fs_1.promises.rm(root, { recursive: true, force: true }); await fs_1.promises.mkdir(root, { recursive: true }); await fs_1.promises.writeFile(path_1.default.join(root, `${bundleIdentifier}.mobileconfig`), profile.replace(/\r?\n/g, '\n')); for (const { languageId, contents } of manifests) { - const languagePath = path_1.default.join(root, languageId === 'en-us' ? 'en-us' : Languages[languageId]); + const languagePath = path_1.default.join(root, languageId === 'en-us' ? 'en-us' : types_1.Languages[languageId]); await fs_1.promises.mkdir(languagePath, { recursive: true }); await fs_1.promises.writeFile(path_1.default.join(languagePath, `${bundleIdentifier}.plist`), contents.replace(/\r?\n/g, '\n')); } diff --git a/build/lib/policies/policyGenerator.ts b/build/lib/policies/policyGenerator.ts index 5fb06942f67..4c5e1d616f7 100644 --- a/build/lib/policies/policyGenerator.ts +++ b/build/lib/policies/policyGenerator.ts @@ -6,693 +6,19 @@ import minimist from 'minimist'; import { promises as fs } from 'fs'; import path from 'path'; -import { CategoryDto, ExportedPolicyDataDto, PolicyDto } from './policyDto'; +import { CategoryDto, ExportedPolicyDataDto } from './policyDto'; import * as JSONC from 'jsonc-parser'; +import { BooleanPolicy } from './booleanPolicy'; +import { NumberPolicy } from './numberPolicy'; +import { ObjectPolicy } from './objectPolicy'; +import { StringEnumPolicy } from './stringEnumPolicy'; +import { StringPolicy } from './stringPolicy'; +import { Version, LanguageTranslations, Policy, Translations, Languages, ProductJson } from './types'; +import { renderGP, renderMacOSPolicy } from './render'; -const product = require('../../../product.json'); +const product = require('../../../product.json') as ProductJson; const packageJson = require('../../../package.json'); -type NlsString = { value: string; nlsKey: string }; - -interface Category { - readonly moduleName: string; - readonly name: NlsString; -} - -enum PolicyType { - Boolean = 'boolean', - Number = 'number', - Object = 'object', - String = 'string', - StringEnum = 'stringEnum', -} - -interface Policy { - readonly name: string; - readonly type: PolicyType; - readonly category: Category; - readonly minimumVersion: string; - renderADMX(regKey: string): string[]; - renderADMLStrings(translations?: LanguageTranslations): string[]; - renderADMLPresentation(): string; - renderProfile(): string[]; - // https://github.com/ProfileManifests/ProfileManifests/wiki/Manifest-Format - renderProfileManifest(translations?: LanguageTranslations): string; -} - -function renderADMLString(prefix: string, moduleName: string, nlsString: NlsString, translations?: LanguageTranslations): string { - let value: string | undefined; - - if (translations) { - const moduleTranslations = translations[moduleName]; - - if (moduleTranslations) { - value = moduleTranslations[nlsString.nlsKey]; - } - } - - if (!value) { - value = nlsString.value; - } - - return `${value}`; -} - -function renderProfileString(_prefix: string, moduleName: string, nlsString: NlsString, translations?: LanguageTranslations): string { - let value: string | undefined; - - if (translations) { - const moduleTranslations = translations[moduleName]; - - if (moduleTranslations) { - value = moduleTranslations[nlsString.nlsKey]; - } - } - - if (!value) { - value = nlsString.value; - } - - return value; -} - -abstract class BasePolicy implements Policy { - constructor( - readonly type: PolicyType, - readonly name: string, - readonly category: Category, - readonly minimumVersion: string, - protected description: NlsString, - protected moduleName: string, - ) { } - - protected renderADMLString(nlsString: NlsString, translations?: LanguageTranslations): string { - return renderADMLString(this.name, this.moduleName, nlsString, translations); - } - - renderADMX(regKey: string) { - return [ - ``, - ` `, - ` `, - ` `, - ...this.renderADMXElements(), - ` `, - `` - ]; - } - - protected abstract renderADMXElements(): string[]; - - renderADMLStrings(translations?: LanguageTranslations) { - return [ - `${this.name}`, - this.renderADMLString(this.description, translations) - ]; - } - - renderADMLPresentation(): string { - return `${this.renderADMLPresentationContents()}`; - } - - protected abstract renderADMLPresentationContents(): string; - - renderProfile() { - return [`${this.name}`, this.renderProfileValue()]; - } - - renderProfileManifest(translations?: LanguageTranslations): string { - return ` -${this.renderProfileManifestValue(translations)} -`; - } - - abstract renderProfileValue(): string; - abstract renderProfileManifestValue(translations?: LanguageTranslations): string; -} - -class BooleanPolicy extends BasePolicy { - - static from(category: CategoryDto, policy: PolicyDto): BooleanPolicy | undefined { - const { name, minimumVersion, localization, type } = policy; - - if (type !== 'boolean') { - return undefined; - } - - return new BooleanPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); - } - - private constructor( - name: string, - category: Category, - minimumVersion: string, - description: NlsString, - moduleName: string, - ) { - super(PolicyType.Boolean, name, category, minimumVersion, description, moduleName); - } - - protected renderADMXElements(): string[] { - return [ - ``, - ` `, - `` - ]; - } - - renderADMLPresentationContents() { - return `${this.name}`; - } - - renderProfileValue(): string { - return ``; - } - - renderProfileManifestValue(translations?: LanguageTranslations): string { - return `pfm_default - -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -boolean`; - } -} - -class NumberPolicy extends BasePolicy { - - static from(category: CategoryDto, policy: PolicyDto): NumberPolicy | undefined { - const { type, default: defaultValue, name, minimumVersion, localization } = policy; - - if (type !== 'number') { - return undefined; - } - - if (typeof defaultValue !== 'number') { - throw new Error(`Missing required 'default' property.`); - } - - return new NumberPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, '', defaultValue); - } - - private constructor( - name: string, - category: Category, - minimumVersion: string, - description: NlsString, - moduleName: string, - protected readonly defaultValue: number, - ) { - super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); - } - - protected renderADMXElements(): string[] { - return [ - `` - // `` - ]; - } - - renderADMLPresentationContents() { - return `${this.name}`; - } - - renderProfileValue() { - return `${this.defaultValue}`; - } - - renderProfileManifestValue(translations?: LanguageTranslations) { - return `pfm_default -${this.defaultValue} -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -integer`; - } -} - -class StringPolicy extends BasePolicy { - - static from(category: CategoryDto, policy: PolicyDto): StringPolicy | undefined { - const { type, name, minimumVersion, localization } = policy; - - if (type !== 'string') { - return undefined; - } - - return new StringPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); - } - - private constructor( - name: string, - category: Category, - minimumVersion: string, - description: NlsString, - moduleName: string, - ) { - super(PolicyType.String, name, category, minimumVersion, description, moduleName); - } - - protected renderADMXElements(): string[] { - return [``]; - } - - renderADMLPresentationContents() { - return ``; - } - - renderProfileValue(): string { - return ``; - } - - renderProfileManifestValue(translations?: LanguageTranslations): string { - return `pfm_default - -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -string`; - } -} - -class ObjectPolicy extends BasePolicy { - - static from(category: CategoryDto, policy: PolicyDto): ObjectPolicy | undefined { - const { type, name, minimumVersion, localization } = policy; - - if (type !== 'object' && type !== 'array') { - return undefined; - } - - return new ObjectPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); - } - - private constructor( - name: string, - category: Category, - minimumVersion: string, - description: NlsString, - moduleName: string, - ) { - super(PolicyType.Object, name, category, minimumVersion, description, moduleName); - } - - protected renderADMXElements(): string[] { - return [``]; - } - - renderADMLPresentationContents() { - return ``; - } - - renderProfileValue(): string { - return ``; - } - - renderProfileManifestValue(translations?: LanguageTranslations): string { - return `pfm_default - -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -string -`; - } -} - -class StringEnumPolicy extends BasePolicy { - - static from(category: CategoryDto, policy: PolicyDto): StringEnumPolicy | undefined { - const { type, name, minimumVersion, enum: enumValue, localization } = policy; - - if (type !== 'string') { - return undefined; - } - - const enum_ = enumValue; - - if (!enum_) { - return undefined; - } - - if (!localization.enumDescriptions || !Array.isArray(localization.enumDescriptions) || localization.enumDescriptions.length !== enum_.length) { - throw new Error(`Invalid policy data: enumDescriptions must exist and have the same length as enum_ for policy "${name}".`); - } - const enumDescriptions = localization.enumDescriptions.map((e) => ({ nlsKey: e.key, value: e.value })); - return new StringEnumPolicy( - name, - { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, - minimumVersion, - { nlsKey: localization.description.key, value: localization.description.value }, - '', - enum_, - enumDescriptions - ); - } - - private constructor( - name: string, - category: Category, - minimumVersion: string, - description: NlsString, - moduleName: string, - protected enum_: string[], - protected enumDescriptions: NlsString[], - ) { - super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); - } - - protected renderADMXElements(): string[] { - return [ - ``, - ...this.enum_.map((value, index) => ` ${value}`), - `` - ]; - } - - renderADMLStrings(translations?: LanguageTranslations) { - return [ - ...super.renderADMLStrings(translations), - ...this.enumDescriptions.map(e => this.renderADMLString(e, translations)) - ]; - } - - renderADMLPresentationContents() { - return ``; - } - - renderProfileValue() { - return `${this.enum_[0]}`; - } - - renderProfileManifestValue(translations?: LanguageTranslations): string { - return `pfm_default -${this.enum_[0]} -pfm_description -${renderProfileString(this.name, this.moduleName, this.description, translations)} -pfm_name -${this.name} -pfm_title -${this.name} -pfm_type -string -pfm_range_list - - ${this.enum_.map(e => `${e}`).join('\n ')} -`; - } -} - -function renderADMX(regKey: string, versions: string[], categories: Category[], policies: Policy[]) { - versions = versions.map(v => v.replace(/\./g, '_')); - - return ` - - - - - - - - ${versions.map(v => ``).join(`\n `)} - - - - - ${categories.map(c => ``).join(`\n `)} - - - ${policies.map(p => p.renderADMX(regKey)).flat().join(`\n `)} - - -`; -} - -function renderADML(appName: string, versions: string[], categories: Category[], policies: Policy[], translations?: LanguageTranslations) { - return ` - - - - - - ${appName} - ${versions.map(v => `${appName} >= ${v}`).join(`\n `)} - ${categories.map(c => renderADMLString('Category', c.moduleName, c.name, translations)).join(`\n `)} - ${policies.map(p => p.renderADMLStrings(translations)).flat().join(`\n `)} - - - ${policies.map(p => p.renderADMLPresentation()).join(`\n `)} - - - -`; -} - -function renderProfileManifest(appName: string, bundleIdentifier: string, _versions: string[], _categories: Category[], policies: Policy[], translations?: LanguageTranslations) { - - const requiredPayloadFields = ` - - pfm_default - Configure ${appName} - pfm_name - PayloadDescription - pfm_title - Payload Description - pfm_type - string - - - pfm_default - ${appName} - pfm_name - PayloadDisplayName - pfm_require - always - pfm_title - Payload Display Name - pfm_type - string - - - pfm_default - ${bundleIdentifier} - pfm_name - PayloadIdentifier - pfm_require - always - pfm_title - Payload Identifier - pfm_type - string - - - pfm_default - ${bundleIdentifier} - pfm_name - PayloadType - pfm_require - always - pfm_title - Payload Type - pfm_type - string - - - pfm_default - - pfm_name - PayloadUUID - pfm_require - always - pfm_title - Payload UUID - pfm_type - string - - - pfm_default - 1 - pfm_name - PayloadVersion - pfm_range_list - - 1 - - pfm_require - always - pfm_title - Payload Version - pfm_type - integer - - - pfm_default - Microsoft - pfm_name - PayloadOrganization - pfm_title - Payload Organization - pfm_type - string - `; - - const profileManifestSubkeys = policies.map(policy => { - return policy.renderProfileManifest(translations); - }).join(''); - - return ` - - - - pfm_app_url - https://code.visualstudio.com/ - pfm_description - ${appName} Managed Settings - pfm_documentation_url - https://code.visualstudio.com/docs/setup/enterprise - pfm_domain - ${bundleIdentifier} - pfm_format_version - 1 - pfm_interaction - combined - pfm_last_modified - ${new Date().toISOString().replace(/\.\d+Z$/, 'Z')} - pfm_platforms - - macOS - - pfm_subkeys - - ${requiredPayloadFields} - ${profileManifestSubkeys} - - pfm_title - ${appName} - pfm_unique - - pfm_version - 1 - -`; -} - -function renderMacOSPolicy(policies: Policy[], translations: Translations) { - const appName = product.nameLong; - const bundleIdentifier = product.darwinBundleIdentifier; - const payloadUUID = product.darwinProfilePayloadUUID; - const UUID = product.darwinProfileUUID; - - const versions = [...new Set(policies.map(p => p.minimumVersion)).values()].sort(); - const categories = [...new Set(policies.map(p => p.category))]; - - const policyEntries = - policies.map(policy => policy.renderProfile()) - .flat() - .map(entry => `\t\t\t\t${entry}`) - .join('\n'); - - - return { - profile: ` - - - - PayloadContent - - - PayloadDisplayName - ${appName} - PayloadIdentifier - ${bundleIdentifier}.${UUID} - PayloadType - ${bundleIdentifier} - PayloadUUID - ${UUID} - PayloadVersion - 1 -${policyEntries} - - - PayloadDescription - This profile manages ${appName}. For more information see https://code.visualstudio.com/docs/setup/enterprise - PayloadDisplayName - ${appName} - PayloadIdentifier - ${bundleIdentifier} - PayloadOrganization - Microsoft - PayloadType - Configuration - PayloadUUID - ${payloadUUID} - PayloadVersion - 1 - TargetDeviceType - 5 - -`, - manifests: [{ languageId: 'en-us', contents: renderProfileManifest(appName, bundleIdentifier, versions, categories, policies) }, - ...translations.map(({ languageId, languageTranslations }) => - ({ languageId, contents: renderProfileManifest(appName, bundleIdentifier, versions, categories, policies, languageTranslations) })) - ] - }; -} - -function renderGP(policies: Policy[], translations: Translations) { - const appName = product.nameLong; - const regKey = product.win32RegValueName; - - const versions = [...new Set(policies.map(p => p.minimumVersion)).values()].sort(); - const categories = [...Object.values(policies.reduce((acc, p) => ({ ...acc, [p.category.name.nlsKey]: p.category }), {}))] as Category[]; - - return { - admx: renderADMX(regKey, versions, categories, policies), - adml: [ - { languageId: 'en-us', contents: renderADML(appName, versions, categories, policies) }, - ...translations.map(({ languageId, languageTranslations }) => - ({ languageId, contents: renderADML(appName, versions, categories, policies, languageTranslations) })) - ] - }; -} - -const Languages = { - 'fr': 'fr-fr', - 'it': 'it-it', - 'de': 'de-de', - 'es': 'es-es', - 'ru': 'ru-ru', - 'zh-hans': 'zh-cn', - 'zh-hant': 'zh-tw', - 'ja': 'ja-jp', - 'ko': 'ko-kr', - 'cs': 'cs-cz', - 'pt-br': 'pt-br', - 'tr': 'tr-tr', - 'pl': 'pl-pl', -}; - -type LanguageTranslations = { [moduleName: string]: { [nlsKey: string]: string } }; -type Translations = { languageId: string; languageTranslations: LanguageTranslations }[]; - -type Version = [number, number, number]; - async function getSpecificNLS(resourceUrlTemplate: string, languageId: string, version: Version): Promise { const resource = { publisher: 'ms-ceintl', @@ -843,7 +169,7 @@ async function getTranslations(): Promise { async function windowsMain(policies: Policy[], translations: Translations) { const root = '.build/policies/win32'; - const { admx, adml } = await renderGP(policies, translations); + const { admx, adml } = renderGP(product, policies, translations); await fs.rm(root, { recursive: true, force: true }); await fs.mkdir(root, { recursive: true }); @@ -863,7 +189,7 @@ async function darwinMain(policies: Policy[], translations: Translations) { throw new Error(`Missing required product information.`); } const root = '.build/policies/darwin'; - const { profile, manifests } = await renderMacOSPolicy(policies, translations); + const { profile, manifests } = renderMacOSPolicy(product, policies, translations); await fs.rm(root, { recursive: true, force: true }); await fs.mkdir(root, { recursive: true }); diff --git a/build/lib/policies/render.js b/build/lib/policies/render.js new file mode 100644 index 00000000000..7f312314e35 --- /dev/null +++ b/build/lib/policies/render.js @@ -0,0 +1,271 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.renderADMLString = renderADMLString; +exports.renderProfileString = renderProfileString; +exports.renderADMX = renderADMX; +exports.renderADML = renderADML; +exports.renderProfileManifest = renderProfileManifest; +exports.renderMacOSPolicy = renderMacOSPolicy; +exports.renderGP = renderGP; +function renderADMLString(prefix, moduleName, nlsString, translations) { + let value; + if (translations) { + const moduleTranslations = translations[moduleName]; + if (moduleTranslations) { + value = moduleTranslations[nlsString.nlsKey]; + } + } + if (!value) { + value = nlsString.value; + } + return `${value}`; +} +function renderProfileString(_prefix, moduleName, nlsString, translations) { + let value; + if (translations) { + const moduleTranslations = translations[moduleName]; + if (moduleTranslations) { + value = moduleTranslations[nlsString.nlsKey]; + } + } + if (!value) { + value = nlsString.value; + } + return value; +} +function renderADMX(regKey, versions, categories, policies) { + versions = versions.map(v => v.replace(/\./g, '_')); + return ` + + + + + + + + ${versions.map(v => ``).join(`\n `)} + + + + + ${categories.map(c => ``).join(`\n `)} + + + ${policies.map(p => p.renderADMX(regKey)).flat().join(`\n `)} + + +`; +} +function renderADML(appName, versions, categories, policies, translations) { + return ` + + + + + + ${appName} + ${versions.map(v => `${appName} >= ${v}`).join(`\n `)} + ${categories.map(c => renderADMLString('Category', c.moduleName, c.name, translations)).join(`\n `)} + ${policies.map(p => p.renderADMLStrings(translations)).flat().join(`\n `)} + + + ${policies.map(p => p.renderADMLPresentation()).join(`\n `)} + + + +`; +} +function renderProfileManifest(appName, bundleIdentifier, _versions, _categories, policies, translations) { + const requiredPayloadFields = ` + + pfm_default + Configure ${appName} + pfm_name + PayloadDescription + pfm_title + Payload Description + pfm_type + string + + + pfm_default + ${appName} + pfm_name + PayloadDisplayName + pfm_require + always + pfm_title + Payload Display Name + pfm_type + string + + + pfm_default + ${bundleIdentifier} + pfm_name + PayloadIdentifier + pfm_require + always + pfm_title + Payload Identifier + pfm_type + string + + + pfm_default + ${bundleIdentifier} + pfm_name + PayloadType + pfm_require + always + pfm_title + Payload Type + pfm_type + string + + + pfm_default + + pfm_name + PayloadUUID + pfm_require + always + pfm_title + Payload UUID + pfm_type + string + + + pfm_default + 1 + pfm_name + PayloadVersion + pfm_range_list + + 1 + + pfm_require + always + pfm_title + Payload Version + pfm_type + integer + + + pfm_default + Microsoft + pfm_name + PayloadOrganization + pfm_title + Payload Organization + pfm_type + string + `; + const profileManifestSubkeys = policies.map(policy => { + return policy.renderProfileManifest(translations); + }).join(''); + return ` + + + + pfm_app_url + https://code.visualstudio.com/ + pfm_description + ${appName} Managed Settings + pfm_documentation_url + https://code.visualstudio.com/docs/setup/enterprise + pfm_domain + ${bundleIdentifier} + pfm_format_version + 1 + pfm_interaction + combined + pfm_last_modified + ${new Date().toISOString().replace(/\.\d+Z$/, 'Z')} + pfm_platforms + + macOS + + pfm_subkeys + + ${requiredPayloadFields} + ${profileManifestSubkeys} + + pfm_title + ${appName} + pfm_unique + + pfm_version + 1 + +`; +} +function renderMacOSPolicy(product, policies, translations) { + const appName = product.nameLong; + const bundleIdentifier = product.darwinBundleIdentifier; + const payloadUUID = product.darwinProfilePayloadUUID; + const UUID = product.darwinProfileUUID; + const versions = [...new Set(policies.map(p => p.minimumVersion)).values()].sort(); + const categories = [...new Set(policies.map(p => p.category))]; + const policyEntries = policies.map(policy => policy.renderProfile()) + .flat() + .map(entry => `\t\t\t\t${entry}`) + .join('\n'); + return { + profile: ` + + + + PayloadContent + + + PayloadDisplayName + ${appName} + PayloadIdentifier + ${bundleIdentifier}.${UUID} + PayloadType + ${bundleIdentifier} + PayloadUUID + ${UUID} + PayloadVersion + 1 +${policyEntries} + + + PayloadDescription + This profile manages ${appName}. For more information see https://code.visualstudio.com/docs/setup/enterprise + PayloadDisplayName + ${appName} + PayloadIdentifier + ${bundleIdentifier} + PayloadOrganization + Microsoft + PayloadType + Configuration + PayloadUUID + ${payloadUUID} + PayloadVersion + 1 + TargetDeviceType + 5 + +`, + manifests: [{ languageId: 'en-us', contents: renderProfileManifest(appName, bundleIdentifier, versions, categories, policies) }, + ...translations.map(({ languageId, languageTranslations }) => ({ languageId, contents: renderProfileManifest(appName, bundleIdentifier, versions, categories, policies, languageTranslations) })) + ] + }; +} +function renderGP(product, policies, translations) { + const appName = product.nameLong; + const regKey = product.win32RegValueName; + const versions = [...new Set(policies.map(p => p.minimumVersion)).values()].sort(); + const categories = [...Object.values(policies.reduce((acc, p) => ({ ...acc, [p.category.name.nlsKey]: p.category }), {}))]; + return { + admx: renderADMX(regKey, versions, categories, policies), + adml: [ + { languageId: 'en-us', contents: renderADML(appName, versions, categories, policies) }, + ...translations.map(({ languageId, languageTranslations }) => ({ languageId, contents: renderADML(appName, versions, categories, policies, languageTranslations) })) + ] + }; +} +//# sourceMappingURL=render.js.map \ No newline at end of file diff --git a/build/lib/policies/render.ts b/build/lib/policies/render.ts new file mode 100644 index 00000000000..8953a6b7fde --- /dev/null +++ b/build/lib/policies/render.ts @@ -0,0 +1,295 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { NlsString, LanguageTranslations, Category, Policy, Translations, ProductJson } from './types'; + +export function renderADMLString(prefix: string, moduleName: string, nlsString: NlsString, translations?: LanguageTranslations): string { + let value: string | undefined; + + if (translations) { + const moduleTranslations = translations[moduleName]; + + if (moduleTranslations) { + value = moduleTranslations[nlsString.nlsKey]; + } + } + + if (!value) { + value = nlsString.value; + } + + return `${value}`; +} + +export function renderProfileString(_prefix: string, moduleName: string, nlsString: NlsString, translations?: LanguageTranslations): string { + let value: string | undefined; + + if (translations) { + const moduleTranslations = translations[moduleName]; + + if (moduleTranslations) { + value = moduleTranslations[nlsString.nlsKey]; + } + } + + if (!value) { + value = nlsString.value; + } + + return value; +} + +export function renderADMX(regKey: string, versions: string[], categories: Category[], policies: Policy[]) { + versions = versions.map(v => v.replace(/\./g, '_')); + + return ` + + + + + + + + ${versions.map(v => ``).join(`\n `)} + + + + + ${categories.map(c => ``).join(`\n `)} + + + ${policies.map(p => p.renderADMX(regKey)).flat().join(`\n `)} + + +`; +} + +export function renderADML(appName: string, versions: string[], categories: Category[], policies: Policy[], translations?: LanguageTranslations) { + return ` + + + + + + ${appName} + ${versions.map(v => `${appName} >= ${v}`).join(`\n `)} + ${categories.map(c => renderADMLString('Category', c.moduleName, c.name, translations)).join(`\n `)} + ${policies.map(p => p.renderADMLStrings(translations)).flat().join(`\n `)} + + + ${policies.map(p => p.renderADMLPresentation()).join(`\n `)} + + + +`; +} + +export function renderProfileManifest(appName: string, bundleIdentifier: string, _versions: string[], _categories: Category[], policies: Policy[], translations?: LanguageTranslations) { + + const requiredPayloadFields = ` + + pfm_default + Configure ${appName} + pfm_name + PayloadDescription + pfm_title + Payload Description + pfm_type + string + + + pfm_default + ${appName} + pfm_name + PayloadDisplayName + pfm_require + always + pfm_title + Payload Display Name + pfm_type + string + + + pfm_default + ${bundleIdentifier} + pfm_name + PayloadIdentifier + pfm_require + always + pfm_title + Payload Identifier + pfm_type + string + + + pfm_default + ${bundleIdentifier} + pfm_name + PayloadType + pfm_require + always + pfm_title + Payload Type + pfm_type + string + + + pfm_default + + pfm_name + PayloadUUID + pfm_require + always + pfm_title + Payload UUID + pfm_type + string + + + pfm_default + 1 + pfm_name + PayloadVersion + pfm_range_list + + 1 + + pfm_require + always + pfm_title + Payload Version + pfm_type + integer + + + pfm_default + Microsoft + pfm_name + PayloadOrganization + pfm_title + Payload Organization + pfm_type + string + `; + + const profileManifestSubkeys = policies.map(policy => { + return policy.renderProfileManifest(translations); + }).join(''); + + return ` + + + + pfm_app_url + https://code.visualstudio.com/ + pfm_description + ${appName} Managed Settings + pfm_documentation_url + https://code.visualstudio.com/docs/setup/enterprise + pfm_domain + ${bundleIdentifier} + pfm_format_version + 1 + pfm_interaction + combined + pfm_last_modified + ${new Date().toISOString().replace(/\.\d+Z$/, 'Z')} + pfm_platforms + + macOS + + pfm_subkeys + + ${requiredPayloadFields} + ${profileManifestSubkeys} + + pfm_title + ${appName} + pfm_unique + + pfm_version + 1 + +`; +} + +export function renderMacOSPolicy(product: ProductJson, policies: Policy[], translations: Translations) { + const appName = product.nameLong; + const bundleIdentifier = product.darwinBundleIdentifier; + const payloadUUID = product.darwinProfilePayloadUUID; + const UUID = product.darwinProfileUUID; + + const versions = [...new Set(policies.map(p => p.minimumVersion)).values()].sort(); + const categories = [...new Set(policies.map(p => p.category))]; + + const policyEntries = + policies.map(policy => policy.renderProfile()) + .flat() + .map(entry => `\t\t\t\t${entry}`) + .join('\n'); + + + return { + profile: ` + + + + PayloadContent + + + PayloadDisplayName + ${appName} + PayloadIdentifier + ${bundleIdentifier}.${UUID} + PayloadType + ${bundleIdentifier} + PayloadUUID + ${UUID} + PayloadVersion + 1 +${policyEntries} + + + PayloadDescription + This profile manages ${appName}. For more information see https://code.visualstudio.com/docs/setup/enterprise + PayloadDisplayName + ${appName} + PayloadIdentifier + ${bundleIdentifier} + PayloadOrganization + Microsoft + PayloadType + Configuration + PayloadUUID + ${payloadUUID} + PayloadVersion + 1 + TargetDeviceType + 5 + +`, + manifests: [{ languageId: 'en-us', contents: renderProfileManifest(appName, bundleIdentifier, versions, categories, policies) }, + ...translations.map(({ languageId, languageTranslations }) => + ({ languageId, contents: renderProfileManifest(appName, bundleIdentifier, versions, categories, policies, languageTranslations) })) + ] + }; +} + +export function renderGP(product: ProductJson, policies: Policy[], translations: Translations) { + const appName = product.nameLong; + const regKey = product.win32RegValueName; + + const versions = [...new Set(policies.map(p => p.minimumVersion)).values()].sort(); + const categories = [...Object.values(policies.reduce((acc, p) => ({ ...acc, [p.category.name.nlsKey]: p.category }), {}))] as Category[]; + + return { + admx: renderADMX(regKey, versions, categories, policies), + adml: [ + { languageId: 'en-us', contents: renderADML(appName, versions, categories, policies) }, + ...translations.map(({ languageId, languageTranslations }) => + ({ languageId, contents: renderADML(appName, versions, categories, policies, languageTranslations) })) + ] + }; +} diff --git a/build/lib/policies/stringEnumPolicy.js b/build/lib/policies/stringEnumPolicy.js new file mode 100644 index 00000000000..03508238bab --- /dev/null +++ b/build/lib/policies/stringEnumPolicy.js @@ -0,0 +1,71 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.StringEnumPolicy = void 0; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const basePolicy_1 = require("./basePolicy"); +const render_1 = require("./render"); +const types_1 = require("./types"); +class StringEnumPolicy extends basePolicy_1.BasePolicy { + enum_; + enumDescriptions; + static from(category, policy) { + const { type, name, minimumVersion, enum: enumValue, localization } = policy; + if (type !== 'string') { + return undefined; + } + const enum_ = enumValue; + if (!enum_) { + return undefined; + } + if (!localization.enumDescriptions || !Array.isArray(localization.enumDescriptions) || localization.enumDescriptions.length !== enum_.length) { + throw new Error(`Invalid policy data: enumDescriptions must exist and have the same length as enum_ for policy "${name}".`); + } + const enumDescriptions = localization.enumDescriptions.map((e) => ({ nlsKey: e.key, value: e.value })); + return new StringEnumPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, '', enum_, enumDescriptions); + } + constructor(name, category, minimumVersion, description, moduleName, enum_, enumDescriptions) { + super(types_1.PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); + this.enum_ = enum_; + this.enumDescriptions = enumDescriptions; + } + renderADMXElements() { + return [ + ``, + ...this.enum_.map((value, index) => ` ${value}`), + `` + ]; + } + renderADMLStrings(translations) { + return [ + ...super.renderADMLStrings(translations), + ...this.enumDescriptions.map(e => this.renderADMLString(e, translations)) + ]; + } + renderADMLPresentationContents() { + return ``; + } + renderProfileValue() { + return `${this.enum_[0]}`; + } + renderProfileManifestValue(translations) { + return `pfm_default +${this.enum_[0]} +pfm_description +${(0, render_1.renderProfileString)(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +string +pfm_range_list + + ${this.enum_.map(e => `${e}`).join('\n ')} +`; + } +} +exports.StringEnumPolicy = StringEnumPolicy; +//# sourceMappingURL=stringEnumPolicy.js.map \ No newline at end of file diff --git a/build/lib/policies/stringEnumPolicy.ts b/build/lib/policies/stringEnumPolicy.ts new file mode 100644 index 00000000000..b8f8263fb68 --- /dev/null +++ b/build/lib/policies/stringEnumPolicy.ts @@ -0,0 +1,92 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BasePolicy } from './basePolicy'; +import { CategoryDto, PolicyDto } from './policyDto'; +import { renderProfileString } from './render'; +import { Category, NlsString, PolicyType, LanguageTranslations } from './types'; + +export class StringEnumPolicy extends BasePolicy { + + static from(category: CategoryDto, policy: PolicyDto): StringEnumPolicy | undefined { + const { type, name, minimumVersion, enum: enumValue, localization } = policy; + + if (type !== 'string') { + return undefined; + } + + const enum_ = enumValue; + + if (!enum_) { + return undefined; + } + + if (!localization.enumDescriptions || !Array.isArray(localization.enumDescriptions) || localization.enumDescriptions.length !== enum_.length) { + throw new Error(`Invalid policy data: enumDescriptions must exist and have the same length as enum_ for policy "${name}".`); + } + const enumDescriptions = localization.enumDescriptions.map((e) => ({ nlsKey: e.key, value: e.value })); + return new StringEnumPolicy( + name, + { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, + minimumVersion, + { nlsKey: localization.description.key, value: localization.description.value }, + '', + enum_, + enumDescriptions + ); + } + + private constructor( + name: string, + category: Category, + minimumVersion: string, + description: NlsString, + moduleName: string, + protected enum_: string[], + protected enumDescriptions: NlsString[], + ) { + super(PolicyType.StringEnum, name, category, minimumVersion, description, moduleName); + } + + protected renderADMXElements(): string[] { + return [ + ``, + ...this.enum_.map((value, index) => ` ${value}`), + `` + ]; + } + + renderADMLStrings(translations?: LanguageTranslations) { + return [ + ...super.renderADMLStrings(translations), + ...this.enumDescriptions.map(e => this.renderADMLString(e, translations)) + ]; + } + + renderADMLPresentationContents() { + return ``; + } + + renderProfileValue() { + return `${this.enum_[0]}`; + } + + renderProfileManifestValue(translations?: LanguageTranslations): string { + return `pfm_default +${this.enum_[0]} +pfm_description +${renderProfileString(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +string +pfm_range_list + + ${this.enum_.map(e => `${e}`).join('\n ')} +`; + } +} diff --git a/build/lib/policies/stringPolicy.js b/build/lib/policies/stringPolicy.js new file mode 100644 index 00000000000..493bc33af40 --- /dev/null +++ b/build/lib/policies/stringPolicy.js @@ -0,0 +1,45 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.StringPolicy = void 0; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const basePolicy_1 = require("./basePolicy"); +const render_1 = require("./render"); +const types_1 = require("./types"); +class StringPolicy extends basePolicy_1.BasePolicy { + static from(category, policy) { + const { type, name, minimumVersion, localization } = policy; + if (type !== 'string') { + return undefined; + } + return new StringPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); + } + constructor(name, category, minimumVersion, description, moduleName) { + super(types_1.PolicyType.String, name, category, minimumVersion, description, moduleName); + } + renderADMXElements() { + return [``]; + } + renderADMLPresentationContents() { + return ``; + } + renderProfileValue() { + return ``; + } + renderProfileManifestValue(translations) { + return `pfm_default + +pfm_description +${(0, render_1.renderProfileString)(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +string`; + } +} +exports.StringPolicy = StringPolicy; +//# sourceMappingURL=stringPolicy.js.map \ No newline at end of file diff --git a/build/lib/policies/stringPolicy.ts b/build/lib/policies/stringPolicy.ts new file mode 100644 index 00000000000..b18160640a8 --- /dev/null +++ b/build/lib/policies/stringPolicy.ts @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BasePolicy } from './basePolicy'; +import { CategoryDto, PolicyDto } from './policyDto'; +import { renderProfileString } from './render'; +import { Category, NlsString, PolicyType, LanguageTranslations } from './types'; + +export class StringPolicy extends BasePolicy { + + static from(category: CategoryDto, policy: PolicyDto): StringPolicy | undefined { + const { type, name, minimumVersion, localization } = policy; + + if (type !== 'string') { + return undefined; + } + + return new StringPolicy(name, { moduleName: '', name: { nlsKey: category.name.key, value: category.name.value } }, minimumVersion, { nlsKey: localization.description.key, value: localization.description.value }, ''); + } + + private constructor( + name: string, + category: Category, + minimumVersion: string, + description: NlsString, + moduleName: string, + ) { + super(PolicyType.String, name, category, minimumVersion, description, moduleName); + } + + protected renderADMXElements(): string[] { + return [``]; + } + + renderADMLPresentationContents() { + return ``; + } + + renderProfileValue(): string { + return ``; + } + + renderProfileManifestValue(translations?: LanguageTranslations): string { + return `pfm_default + +pfm_description +${renderProfileString(this.name, this.moduleName, this.description, translations)} +pfm_name +${this.name} +pfm_title +${this.name} +pfm_type +string`; + } +} diff --git a/build/lib/policies/types.js b/build/lib/policies/types.js new file mode 100644 index 00000000000..f0456389d79 --- /dev/null +++ b/build/lib/policies/types.js @@ -0,0 +1,27 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Languages = exports.PolicyType = void 0; +var PolicyType; +(function (PolicyType) { + PolicyType["Boolean"] = "boolean"; + PolicyType["Number"] = "number"; + PolicyType["Object"] = "object"; + PolicyType["String"] = "string"; + PolicyType["StringEnum"] = "stringEnum"; +})(PolicyType || (exports.PolicyType = PolicyType = {})); +exports.Languages = { + 'fr': 'fr-fr', + 'it': 'it-it', + 'de': 'de-de', + 'es': 'es-es', + 'ru': 'ru-ru', + 'zh-hans': 'zh-cn', + 'zh-hant': 'zh-tw', + 'ja': 'ja-jp', + 'ko': 'ko-kr', + 'cs': 'cs-cz', + 'pt-br': 'pt-br', + 'tr': 'tr-tr', + 'pl': 'pl-pl', +}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/build/lib/policies/types.ts b/build/lib/policies/types.ts new file mode 100644 index 00000000000..35e93c435ef --- /dev/null +++ b/build/lib/policies/types.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export interface ProductJson { + readonly nameLong: string; + readonly darwinBundleIdentifier: string; + readonly darwinProfilePayloadUUID: string; + readonly darwinProfileUUID: string; + readonly win32RegValueName: string; + readonly extensionsGallery?: { + readonly serviceUrl: string; + readonly resourceUrlTemplate: string; + }; +} + +export interface Policy { + readonly name: string; + readonly type: PolicyType; + readonly category: Category; + readonly minimumVersion: string; + renderADMX(regKey: string): string[]; + renderADMLStrings(translations?: LanguageTranslations): string[]; + renderADMLPresentation(): string; + renderProfile(): string[]; + // https://github.com/ProfileManifests/ProfileManifests/wiki/Manifest-Format + renderProfileManifest(translations?: LanguageTranslations): string; +} + +export type NlsString = { value: string; nlsKey: string }; + +export interface Category { + readonly moduleName: string; + readonly name: NlsString; +} + +export enum PolicyType { + Boolean = 'boolean', + Number = 'number', + Object = 'object', + String = 'string', + StringEnum = 'stringEnum', +} + +export const Languages = { + 'fr': 'fr-fr', + 'it': 'it-it', + 'de': 'de-de', + 'es': 'es-es', + 'ru': 'ru-ru', + 'zh-hans': 'zh-cn', + 'zh-hant': 'zh-tw', + 'ja': 'ja-jp', + 'ko': 'ko-kr', + 'cs': 'cs-cz', + 'pt-br': 'pt-br', + 'tr': 'tr-tr', + 'pl': 'pl-pl', +}; + +export type LanguageTranslations = { [moduleName: string]: { [nlsKey: string]: string } }; +export type Translations = { languageId: string; languageTranslations: LanguageTranslations }[]; + +export type Version = [number, number, number]; diff --git a/build/lib/test/booleanPolicy.test.js b/build/lib/test/booleanPolicy.test.js new file mode 100644 index 00000000000..65bb0f5b88e --- /dev/null +++ b/build/lib/test/booleanPolicy.test.js @@ -0,0 +1,120 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const assert_1 = __importDefault(require("assert")); +const booleanPolicy_js_1 = require("../policies/booleanPolicy.js"); +const types_js_1 = require("../policies/types.js"); +suite('BooleanPolicy', () => { + const mockCategory = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + const mockPolicy = { + key: 'test.boolean.policy', + name: 'TestBooleanPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'boolean', + localization: { + description: { key: 'test.policy.description', value: 'Test policy description' } + } + }; + test('should create BooleanPolicy from factory method', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + assert_1.default.strictEqual(policy.name, 'TestBooleanPolicy'); + assert_1.default.strictEqual(policy.minimumVersion, '1.0'); + assert_1.default.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert_1.default.strictEqual(policy.category.name.value, mockCategory.name.value); + assert_1.default.strictEqual(policy.type, types_js_1.PolicyType.Boolean); + }); + test('should render ADMX elements correctly', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admx = policy.renderADMX('TestKey'); + assert_1.default.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\t', + '', + '\t', + '' + ]); + }); + test('should render ADML strings correctly', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admlStrings = policy.renderADMLStrings(); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestBooleanPolicy', + 'Test policy description' + ]); + }); + test('should render ADML strings with translations', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated description' + } + }; + const admlStrings = policy.renderADMLStrings(translations); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestBooleanPolicy', + 'Translated description' + ]); + }); + test('should render ADML presentation correctly', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const presentation = policy.renderADMLPresentation(); + assert_1.default.strictEqual(presentation, 'TestBooleanPolicy'); + }); + test('should render profile value correctly', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profileValue = policy.renderProfileValue(); + assert_1.default.strictEqual(profileValue, ''); + }); + test('should render profile correctly', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profile = policy.renderProfile(); + assert_1.default.strictEqual(profile.length, 2); + assert_1.default.strictEqual(profile[0], 'TestBooleanPolicy'); + assert_1.default.strictEqual(profile[1], ''); + }); + test('should render profile manifest value correctly', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifestValue = policy.renderProfileManifestValue(); + assert_1.default.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTest policy description\npfm_name\nTestBooleanPolicy\npfm_title\nTestBooleanPolicy\npfm_type\nboolean'); + }); + test('should render profile manifest value with translations', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + const manifestValue = policy.renderProfileManifestValue(translations); + assert_1.default.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTranslated manifest description\npfm_name\nTestBooleanPolicy\npfm_title\nTestBooleanPolicy\npfm_type\nboolean'); + }); + test('should render profile manifest correctly', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifest = policy.renderProfileManifest(); + assert_1.default.strictEqual(manifest, '\npfm_default\n\npfm_description\nTest policy description\npfm_name\nTestBooleanPolicy\npfm_title\nTestBooleanPolicy\npfm_type\nboolean\n'); + }); +}); +//# sourceMappingURL=booleanPolicy.test.js.map \ No newline at end of file diff --git a/build/lib/test/booleanPolicy.test.ts b/build/lib/test/booleanPolicy.test.ts new file mode 100644 index 00000000000..eed38d99d00 --- /dev/null +++ b/build/lib/test/booleanPolicy.test.ts @@ -0,0 +1,158 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { BooleanPolicy } from '../policies/booleanPolicy.js'; +import { LanguageTranslations, PolicyType } from '../policies/types.js'; +import { CategoryDto, PolicyDto } from '../policies/policyDto.js'; + +suite('BooleanPolicy', () => { + const mockCategory: CategoryDto = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + + const mockPolicy: PolicyDto = { + key: 'test.boolean.policy', + name: 'TestBooleanPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'boolean', + localization: { + description: { key: 'test.policy.description', value: 'Test policy description' } + } + }; + + test('should create BooleanPolicy from factory method', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + assert.strictEqual(policy.name, 'TestBooleanPolicy'); + assert.strictEqual(policy.minimumVersion, '1.0'); + assert.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert.strictEqual(policy.category.name.value, mockCategory.name.value); + assert.strictEqual(policy.type, PolicyType.Boolean); + }); + + test('should render ADMX elements correctly', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admx = policy.renderADMX('TestKey'); + + assert.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\t', + '', + '\t', + '' + ]); + }); + + test('should render ADML strings correctly', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admlStrings = policy.renderADMLStrings(); + + assert.deepStrictEqual(admlStrings, [ + 'TestBooleanPolicy', + 'Test policy description' + ]); + }); + + test('should render ADML strings with translations', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated description' + } + }; + + const admlStrings = policy.renderADMLStrings(translations); + + assert.deepStrictEqual(admlStrings, [ + 'TestBooleanPolicy', + 'Translated description' + ]); + }); + + test('should render ADML presentation correctly', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const presentation = policy.renderADMLPresentation(); + + assert.strictEqual(presentation, 'TestBooleanPolicy'); + }); + + test('should render profile value correctly', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profileValue = policy.renderProfileValue(); + + assert.strictEqual(profileValue, ''); + }); + + test('should render profile correctly', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profile = policy.renderProfile(); + + assert.strictEqual(profile.length, 2); + assert.strictEqual(profile[0], 'TestBooleanPolicy'); + assert.strictEqual(profile[1], ''); + }); + + test('should render profile manifest value correctly', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifestValue = policy.renderProfileManifestValue(); + + assert.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTest policy description\npfm_name\nTestBooleanPolicy\npfm_title\nTestBooleanPolicy\npfm_type\nboolean'); + }); + + test('should render profile manifest value with translations', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + + const manifestValue = policy.renderProfileManifestValue(translations); + + assert.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTranslated manifest description\npfm_name\nTestBooleanPolicy\npfm_title\nTestBooleanPolicy\npfm_type\nboolean'); + }); + + test('should render profile manifest correctly', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifest = policy.renderProfileManifest(); + + assert.strictEqual(manifest, '\npfm_default\n\npfm_description\nTest policy description\npfm_name\nTestBooleanPolicy\npfm_title\nTestBooleanPolicy\npfm_type\nboolean\n'); + }); +}); diff --git a/build/lib/test/fixtures/policies/darwin/com.visualstudio.code.oss.mobileconfig b/build/lib/test/fixtures/policies/darwin/com.visualstudio.code.oss.mobileconfig new file mode 100644 index 00000000000..0f0ae365d7c --- /dev/null +++ b/build/lib/test/fixtures/policies/darwin/com.visualstudio.code.oss.mobileconfig @@ -0,0 +1,61 @@ + + + + + PayloadContent + + + PayloadDisplayName + Code - OSS + PayloadIdentifier + com.visualstudio.code.oss.47827DD9-4734-49A0-AF80-7E19B11495CC + PayloadType + com.visualstudio.code.oss + PayloadUUID + 47827DD9-4734-49A0-AF80-7E19B11495CC + PayloadVersion + 1 + ChatAgentExtensionTools + + ChatAgentMode + + ChatMCP + none + ChatPromptFiles + + ChatToolsAutoApprove + + McpGalleryServiceUrl + + AllowedExtensions + + ExtensionGalleryServiceUrl + + ChatToolsTerminalEnableAutoApprove + + EnableFeedback + + TelemetryLevel + all + UpdateMode + none + + + PayloadDescription + This profile manages Code - OSS. For more information see https://code.visualstudio.com/docs/setup/enterprise + PayloadDisplayName + Code - OSS + PayloadIdentifier + com.visualstudio.code.oss + PayloadOrganization + Microsoft + PayloadType + Configuration + PayloadUUID + CF808BE7-53F3-46C6-A7E2-7EDB98A5E959 + PayloadVersion + 1 + TargetDeviceType + 5 + + \ No newline at end of file diff --git a/build/lib/test/fixtures/policies/darwin/en-us/com.visualstudio.code.oss.plist b/build/lib/test/fixtures/policies/darwin/en-us/com.visualstudio.code.oss.plist new file mode 100644 index 00000000000..f90533cfeaa --- /dev/null +++ b/build/lib/test/fixtures/policies/darwin/en-us/com.visualstudio.code.oss.plist @@ -0,0 +1,274 @@ + + + + + pfm_app_url + https://code.visualstudio.com/ + pfm_description + Code - OSS Managed Settings + pfm_documentation_url + https://code.visualstudio.com/docs/setup/enterprise + pfm_domain + com.visualstudio.code.oss + pfm_format_version + 1 + pfm_interaction + combined + pfm_last_modified + 2025-10-21T23:04:34Z + pfm_platforms + + macOS + + pfm_subkeys + + + + pfm_default + Configure Code - OSS + pfm_name + PayloadDescription + pfm_title + Payload Description + pfm_type + string + + + pfm_default + Code - OSS + pfm_name + PayloadDisplayName + pfm_require + always + pfm_title + Payload Display Name + pfm_type + string + + + pfm_default + com.visualstudio.code.oss + pfm_name + PayloadIdentifier + pfm_require + always + pfm_title + Payload Identifier + pfm_type + string + + + pfm_default + com.visualstudio.code.oss + pfm_name + PayloadType + pfm_require + always + pfm_title + Payload Type + pfm_type + string + + + pfm_default + + pfm_name + PayloadUUID + pfm_require + always + pfm_title + Payload UUID + pfm_type + string + + + pfm_default + 1 + pfm_name + PayloadVersion + pfm_range_list + + 1 + + pfm_require + always + pfm_title + Payload Version + pfm_type + integer + + + pfm_default + Microsoft + pfm_name + PayloadOrganization + pfm_title + Payload Organization + pfm_type + string + + +pfm_default + +pfm_description +Enable using tools contributed by third-party extensions. +pfm_name +ChatAgentExtensionTools +pfm_title +ChatAgentExtensionTools +pfm_type +boolean + +pfm_default + +pfm_description +Enable agent mode for chat. When this is enabled, agent mode can be activated via the dropdown in the view. +pfm_name +ChatAgentMode +pfm_title +ChatAgentMode +pfm_type +boolean + +pfm_default +none +pfm_description +Controls access to installed Model Context Protocol servers. +pfm_name +ChatMCP +pfm_title +ChatMCP +pfm_type +string +pfm_range_list + + none + registry + all + + +pfm_default + +pfm_description +Enables reusable prompt and instruction files in Chat sessions. +pfm_name +ChatPromptFiles +pfm_title +ChatPromptFiles +pfm_type +boolean + +pfm_default + +pfm_description +Global auto approve also known as "YOLO mode" disables manual approval completely for all tools in all workspaces, allowing the agent to act fully autonomously. This is extremely dangerous and is *never* recommended, even containerized environments like Codespaces and Dev Containers have user keys forwarded into the container that could be compromised. + +This feature disables critical security protections and makes it much easier for an attacker to compromise the machine. +pfm_name +ChatToolsAutoApprove +pfm_title +ChatToolsAutoApprove +pfm_type +boolean + +pfm_default + +pfm_description +Configure the MCP Gallery service URL to connect to +pfm_name +McpGalleryServiceUrl +pfm_title +McpGalleryServiceUrl +pfm_type +string + +pfm_default + +pfm_description +Specify a list of extensions that are allowed to use. This helps maintain a secure and consistent development environment by restricting the use of unauthorized extensions. More information: https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions +pfm_name +AllowedExtensions +pfm_title +AllowedExtensions +pfm_type +string + + +pfm_default + +pfm_description +Configure the Marketplace service URL to connect to +pfm_name +ExtensionGalleryServiceUrl +pfm_title +ExtensionGalleryServiceUrl +pfm_type +string + +pfm_default + +pfm_description +Controls whether to allow auto approval in the run in terminal tool. +pfm_name +ChatToolsTerminalEnableAutoApprove +pfm_title +ChatToolsTerminalEnableAutoApprove +pfm_type +boolean + +pfm_default + +pfm_description +Enable feedback mechanisms such as the issue reporter, surveys, and other feedback options. +pfm_name +EnableFeedback +pfm_title +EnableFeedback +pfm_type +boolean + +pfm_default +all +pfm_description +Controls the level of telemetry. +pfm_name +TelemetryLevel +pfm_title +TelemetryLevel +pfm_type +string +pfm_range_list + + all + error + crash + off + + +pfm_default +none +pfm_description +Configure whether you receive automatic updates. Requires a restart after change. The updates are fetched from a Microsoft online service. +pfm_name +UpdateMode +pfm_title +UpdateMode +pfm_type +string +pfm_range_list + + none + manual + start + default + + + + pfm_title + Code - OSS + pfm_unique + + pfm_version + 1 + + \ No newline at end of file diff --git a/build/lib/test/fixtures/policies/darwin/fr-fr/com.visualstudio.code.oss.plist b/build/lib/test/fixtures/policies/darwin/fr-fr/com.visualstudio.code.oss.plist new file mode 100644 index 00000000000..60f244be3b5 --- /dev/null +++ b/build/lib/test/fixtures/policies/darwin/fr-fr/com.visualstudio.code.oss.plist @@ -0,0 +1,274 @@ + + + + + pfm_app_url + https://code.visualstudio.com/ + pfm_description + Code - OSS Managed Settings + pfm_documentation_url + https://code.visualstudio.com/docs/setup/enterprise + pfm_domain + com.visualstudio.code.oss + pfm_format_version + 1 + pfm_interaction + combined + pfm_last_modified + 2025-10-21T23:04:34Z + pfm_platforms + + macOS + + pfm_subkeys + + + + pfm_default + Configure Code - OSS + pfm_name + PayloadDescription + pfm_title + Payload Description + pfm_type + string + + + pfm_default + Code - OSS + pfm_name + PayloadDisplayName + pfm_require + always + pfm_title + Payload Display Name + pfm_type + string + + + pfm_default + com.visualstudio.code.oss + pfm_name + PayloadIdentifier + pfm_require + always + pfm_title + Payload Identifier + pfm_type + string + + + pfm_default + com.visualstudio.code.oss + pfm_name + PayloadType + pfm_require + always + pfm_title + Payload Type + pfm_type + string + + + pfm_default + + pfm_name + PayloadUUID + pfm_require + always + pfm_title + Payload UUID + pfm_type + string + + + pfm_default + 1 + pfm_name + PayloadVersion + pfm_range_list + + 1 + + pfm_require + always + pfm_title + Payload Version + pfm_type + integer + + + pfm_default + Microsoft + pfm_name + PayloadOrganization + pfm_title + Payload Organization + pfm_type + string + + +pfm_default + +pfm_description +Autorisez l’utilisation d’outils fournis par des extensions tierces. +pfm_name +ChatAgentExtensionTools +pfm_title +ChatAgentExtensionTools +pfm_type +boolean + +pfm_default + +pfm_description +Activez le mode Assistant pour la conversation. Lorsque cette option est activée, le mode Assistant peut être activé via la liste déroulante de la vue. +pfm_name +ChatAgentMode +pfm_title +ChatAgentMode +pfm_type +boolean + +pfm_default +none +pfm_description +Contrôle l’accès aux serveurs de protocole de contexte du modèle. +pfm_name +ChatMCP +pfm_title +ChatMCP +pfm_type +string +pfm_range_list + + none + registry + all + + +pfm_default + +pfm_description +Active les fichiers d’instruction et de requête réutilisables dans les sessions Conversation. +pfm_name +ChatPromptFiles +pfm_title +ChatPromptFiles +pfm_type +boolean + +pfm_default + +pfm_description +L’approbation automatique globale, également appelée « mode YOLO », désactive complètement l’approbation manuelle pour tous les outils dans tous les espaces de travail, permettant à l’agent d’agir de manière totalement autonome. Ceci est extrêmement dangereux et est *jamais* recommandé, même dans des environnements conteneurisés comme [Codespaces](https://github.com/features/codespaces) et [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), où des clés utilisateur sont transférées dans le conteneur et pourraient être compromises. + +Cette fonctionnalité désactive [les protections de sécurité critiques](https://code.visualstudio.com/docs/copilot/security) et facilite considérablement la compromission de la machine par un attaquant. +pfm_name +ChatToolsAutoApprove +pfm_title +ChatToolsAutoApprove +pfm_type +boolean + +pfm_default + +pfm_description +Configurer l’URL du service de la galerie MCP à laquelle se connecter +pfm_name +McpGalleryServiceUrl +pfm_title +McpGalleryServiceUrl +pfm_type +string + +pfm_default + +pfm_description +Spécifiez une liste d’extensions autorisées. Cela permet de maintenir un environnement de développement sécurisé et cohérent en limitant l’utilisation d’extensions non autorisées. Plus d’informations : https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions +pfm_name +AllowedExtensions +pfm_title +AllowedExtensions +pfm_type +string + + +pfm_default + +pfm_description +Configurer l’URL du service Place de marché à laquelle se connecter +pfm_name +ExtensionGalleryServiceUrl +pfm_title +ExtensionGalleryServiceUrl +pfm_type +string + +pfm_default + +pfm_description +Contrôle s’il faut autoriser l’approbation automatique lors de l’exécution dans l’outil terminal. +pfm_name +ChatToolsTerminalEnableAutoApprove +pfm_title +ChatToolsTerminalEnableAutoApprove +pfm_type +boolean + +pfm_default + +pfm_description +Activez les mécanismes de commentaires tels que le système de rapport de problèmes, les sondages et autres options de commentaires. +pfm_name +EnableFeedback +pfm_title +EnableFeedback +pfm_type +boolean + +pfm_default +all +pfm_description +Contrôle le niveau de télémétrie. +pfm_name +TelemetryLevel +pfm_title +TelemetryLevel +pfm_type +string +pfm_range_list + + all + error + crash + off + + +pfm_default +none +pfm_description +Choisissez si vous voulez recevoir des mises à jour automatiques. Nécessite un redémarrage après le changement. Les mises à jour sont récupérées auprès d'un service en ligne Microsoft. +pfm_name +UpdateMode +pfm_title +UpdateMode +pfm_type +string +pfm_range_list + + none + manual + start + default + + + + pfm_title + Code - OSS + pfm_unique + + pfm_version + 1 + + \ No newline at end of file diff --git a/build/lib/test/fixtures/policies/win32/CodeOSS.admx b/build/lib/test/fixtures/policies/win32/CodeOSS.admx new file mode 100644 index 00000000000..fee094c56c5 --- /dev/null +++ b/build/lib/test/fixtures/policies/win32/CodeOSS.admx @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + registry + all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + error + crash + off + + + + + + + + + none + manual + start + default + + + + + diff --git a/build/lib/test/fixtures/policies/win32/en-us/CodeOSS.adml b/build/lib/test/fixtures/policies/win32/en-us/CodeOSS.adml new file mode 100644 index 00000000000..39b05ddc72d --- /dev/null +++ b/build/lib/test/fixtures/policies/win32/en-us/CodeOSS.adml @@ -0,0 +1,71 @@ + + + + + + + Code - OSS + Code - OSS >= 1.101 + Code - OSS >= 1.104 + Code - OSS >= 1.67 + Code - OSS >= 1.96 + Code - OSS >= 1.99 + Chat + Extensions + Integrated Terminal + Telemetry + Update + ChatAgentExtensionTools + Enable using tools contributed by third-party extensions. + ChatAgentMode + Enable agent mode for chat. When this is enabled, agent mode can be activated via the dropdown in the view. + ChatMCP + Controls access to installed Model Context Protocol servers. + No access to MCP servers. + Allows access to MCP servers installed from the registry that VS Code is connected to. + Allow access to any installed MCP server. + ChatPromptFiles + Enables reusable prompt and instruction files in Chat sessions. + ChatToolsAutoApprove + Global auto approve also known as "YOLO mode" disables manual approval completely for all tools in all workspaces, allowing the agent to act fully autonomously. This is extremely dangerous and is *never* recommended, even containerized environments like Codespaces and Dev Containers have user keys forwarded into the container that could be compromised. + +This feature disables critical security protections and makes it much easier for an attacker to compromise the machine. + McpGalleryServiceUrl + Configure the MCP Gallery service URL to connect to + AllowedExtensions + Specify a list of extensions that are allowed to use. This helps maintain a secure and consistent development environment by restricting the use of unauthorized extensions. More information: https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions + ExtensionGalleryServiceUrl + Configure the Marketplace service URL to connect to + ChatToolsTerminalEnableAutoApprove + Controls whether to allow auto approval in the run in terminal tool. + EnableFeedback + Enable feedback mechanisms such as the issue reporter, surveys, and other feedback options. + TelemetryLevel + Controls the level of telemetry. + Sends usage data, errors, and crash reports. + Sends general error telemetry and crash reports. + Sends OS level crash reports. + Disables all product telemetry. + UpdateMode + Configure whether you receive automatic updates. Requires a restart after change. The updates are fetched from a Microsoft online service. + Disable updates. + Disable automatic background update checks. Updates will be available if you manually check for updates. + Check for updates only on startup. Disable automatic background update checks. + Enable automatic update checks. Code will check for updates automatically and periodically. + + + ChatAgentExtensionTools + ChatAgentMode + + ChatPromptFiles + ChatToolsAutoApprove + + + + ChatToolsTerminalEnableAutoApprove + EnableFeedback + + + + + diff --git a/build/lib/test/fixtures/policies/win32/fr-fr/CodeOSS.adml b/build/lib/test/fixtures/policies/win32/fr-fr/CodeOSS.adml new file mode 100644 index 00000000000..eab50282b2d --- /dev/null +++ b/build/lib/test/fixtures/policies/win32/fr-fr/CodeOSS.adml @@ -0,0 +1,71 @@ + + + + + + + Code - OSS + Code - OSS >= 1.101 + Code - OSS >= 1.104 + Code - OSS >= 1.67 + Code - OSS >= 1.96 + Code - OSS >= 1.99 + Session interactive + Extensions + Terminal intégré + Télémétrie + Mettre à jour + ChatAgentExtensionTools + Autorisez l’utilisation d’outils fournis par des extensions tierces. + ChatAgentMode + Activez le mode Assistant pour la conversation. Lorsque cette option est activée, le mode Assistant peut être activé via la liste déroulante de la vue. + ChatMCP + Contrôle l’accès aux serveurs de protocole de contexte du modèle. + Aucun accès aux serveurs MCP. + Autorise l’accès aux serveurs MCP installés à partir du registre auquel VS Code est connecté. + Autorisez l’accès à tout serveur MCP installé. + ChatPromptFiles + Active les fichiers d’instruction et de requête réutilisables dans les sessions Conversation. + ChatToolsAutoApprove + L’approbation automatique globale, également appelée « mode YOLO », désactive complètement l’approbation manuelle pour tous les outils dans tous les espaces de travail, permettant à l’agent d’agir de manière totalement autonome. Ceci est extrêmement dangereux et est *jamais* recommandé, même dans des environnements conteneurisés comme [Codespaces](https://github.com/features/codespaces) et [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), où des clés utilisateur sont transférées dans le conteneur et pourraient être compromises. + +Cette fonctionnalité désactive [les protections de sécurité critiques](https://code.visualstudio.com/docs/copilot/security) et facilite considérablement la compromission de la machine par un attaquant. + McpGalleryServiceUrl + Configurer l’URL du service de la galerie MCP à laquelle se connecter + AllowedExtensions + Spécifiez une liste d’extensions autorisées. Cela permet de maintenir un environnement de développement sécurisé et cohérent en limitant l’utilisation d’extensions non autorisées. Plus d’informations : https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions + ExtensionGalleryServiceUrl + Configurer l’URL du service Place de marché à laquelle se connecter + ChatToolsTerminalEnableAutoApprove + Contrôle s’il faut autoriser l’approbation automatique lors de l’exécution dans l’outil terminal. + EnableFeedback + Activez les mécanismes de commentaires tels que le système de rapport de problèmes, les sondages et autres options de commentaires. + TelemetryLevel + Contrôle le niveau de télémétrie. + Envoie les données d'utilisation, les erreurs et les rapports d'erreur. + Envoie la télémétrie d'erreur générale et les rapports de plantage. + Envoie des rapports de plantage au niveau du système d'exploitation. + Désactive toutes les données de télémétrie du produit. + UpdateMode + Choisissez si vous voulez recevoir des mises à jour automatiques. Nécessite un redémarrage après le changement. Les mises à jour sont récupérées auprès d'un service en ligne Microsoft. + Aucun + Désactivez la recherche de mises à jour automatique en arrière-plan. Les mises à jour sont disponibles si vous les rechercher manuellement. + Démarrer + Système + + + ChatAgentExtensionTools + ChatAgentMode + + ChatPromptFiles + ChatToolsAutoApprove + + + + ChatToolsTerminalEnableAutoApprove + EnableFeedback + + + + + diff --git a/build/lib/test/numberPolicy.test.js b/build/lib/test/numberPolicy.test.js new file mode 100644 index 00000000000..de3a73565be --- /dev/null +++ b/build/lib/test/numberPolicy.test.js @@ -0,0 +1,119 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const assert_1 = __importDefault(require("assert")); +const numberPolicy_js_1 = require("../policies/numberPolicy.js"); +const types_js_1 = require("../policies/types.js"); +suite('NumberPolicy', () => { + const mockCategory = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + const mockPolicy = { + key: 'test.number.policy', + name: 'TestNumberPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'number', + default: 42, + localization: { + description: { key: 'test.policy.description', value: 'Test number policy description' } + } + }; + test('should create NumberPolicy from factory method', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + assert_1.default.strictEqual(policy.name, 'TestNumberPolicy'); + assert_1.default.strictEqual(policy.minimumVersion, '1.0'); + assert_1.default.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert_1.default.strictEqual(policy.category.name.value, mockCategory.name.value); + assert_1.default.strictEqual(policy.type, types_js_1.PolicyType.Number); + }); + test('should render ADMX elements correctly', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admx = policy.renderADMX('TestKey'); + assert_1.default.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\t', + '' + ]); + }); + test('should render ADML strings correctly', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admlStrings = policy.renderADMLStrings(); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestNumberPolicy', + 'Test number policy description' + ]); + }); + test('should render ADML strings with translations', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated description' + } + }; + const admlStrings = policy.renderADMLStrings(translations); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestNumberPolicy', + 'Translated description' + ]); + }); + test('should render ADML presentation correctly', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const presentation = policy.renderADMLPresentation(); + assert_1.default.strictEqual(presentation, 'TestNumberPolicy'); + }); + test('should render profile value correctly', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profileValue = policy.renderProfileValue(); + assert_1.default.strictEqual(profileValue, '42'); + }); + test('should render profile correctly', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profile = policy.renderProfile(); + assert_1.default.strictEqual(profile.length, 2); + assert_1.default.strictEqual(profile[0], 'TestNumberPolicy'); + assert_1.default.strictEqual(profile[1], '42'); + }); + test('should render profile manifest value correctly', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifestValue = policy.renderProfileManifestValue(); + assert_1.default.strictEqual(manifestValue, 'pfm_default\n42\npfm_description\nTest number policy description\npfm_name\nTestNumberPolicy\npfm_title\nTestNumberPolicy\npfm_type\ninteger'); + }); + test('should render profile manifest value with translations', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + const manifestValue = policy.renderProfileManifestValue(translations); + assert_1.default.strictEqual(manifestValue, 'pfm_default\n42\npfm_description\nTranslated manifest description\npfm_name\nTestNumberPolicy\npfm_title\nTestNumberPolicy\npfm_type\ninteger'); + }); + test('should render profile manifest correctly', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifest = policy.renderProfileManifest(); + assert_1.default.strictEqual(manifest, '\npfm_default\n42\npfm_description\nTest number policy description\npfm_name\nTestNumberPolicy\npfm_title\nTestNumberPolicy\npfm_type\ninteger\n'); + }); +}); +//# sourceMappingURL=numberPolicy.test.js.map \ No newline at end of file diff --git a/build/lib/test/numberPolicy.test.ts b/build/lib/test/numberPolicy.test.ts new file mode 100644 index 00000000000..4f27891ec61 --- /dev/null +++ b/build/lib/test/numberPolicy.test.ts @@ -0,0 +1,157 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { NumberPolicy } from '../policies/numberPolicy.js'; +import { LanguageTranslations, PolicyType } from '../policies/types.js'; +import { CategoryDto, PolicyDto } from '../policies/policyDto.js'; + +suite('NumberPolicy', () => { + const mockCategory: CategoryDto = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + + const mockPolicy: PolicyDto = { + key: 'test.number.policy', + name: 'TestNumberPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'number', + default: 42, + localization: { + description: { key: 'test.policy.description', value: 'Test number policy description' } + } + }; + + test('should create NumberPolicy from factory method', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + assert.strictEqual(policy.name, 'TestNumberPolicy'); + assert.strictEqual(policy.minimumVersion, '1.0'); + assert.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert.strictEqual(policy.category.name.value, mockCategory.name.value); + assert.strictEqual(policy.type, PolicyType.Number); + }); + + test('should render ADMX elements correctly', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admx = policy.renderADMX('TestKey'); + + assert.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\t', + '' + ]); + }); + + test('should render ADML strings correctly', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admlStrings = policy.renderADMLStrings(); + + assert.deepStrictEqual(admlStrings, [ + 'TestNumberPolicy', + 'Test number policy description' + ]); + }); + + test('should render ADML strings with translations', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated description' + } + }; + + const admlStrings = policy.renderADMLStrings(translations); + + assert.deepStrictEqual(admlStrings, [ + 'TestNumberPolicy', + 'Translated description' + ]); + }); + + test('should render ADML presentation correctly', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const presentation = policy.renderADMLPresentation(); + + assert.strictEqual(presentation, 'TestNumberPolicy'); + }); + + test('should render profile value correctly', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profileValue = policy.renderProfileValue(); + + assert.strictEqual(profileValue, '42'); + }); + + test('should render profile correctly', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profile = policy.renderProfile(); + + assert.strictEqual(profile.length, 2); + assert.strictEqual(profile[0], 'TestNumberPolicy'); + assert.strictEqual(profile[1], '42'); + }); + + test('should render profile manifest value correctly', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifestValue = policy.renderProfileManifestValue(); + + assert.strictEqual(manifestValue, 'pfm_default\n42\npfm_description\nTest number policy description\npfm_name\nTestNumberPolicy\npfm_title\nTestNumberPolicy\npfm_type\ninteger'); + }); + + test('should render profile manifest value with translations', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + + const manifestValue = policy.renderProfileManifestValue(translations); + + assert.strictEqual(manifestValue, 'pfm_default\n42\npfm_description\nTranslated manifest description\npfm_name\nTestNumberPolicy\npfm_title\nTestNumberPolicy\npfm_type\ninteger'); + }); + + test('should render profile manifest correctly', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifest = policy.renderProfileManifest(); + + assert.strictEqual(manifest, '\npfm_default\n42\npfm_description\nTest number policy description\npfm_name\nTestNumberPolicy\npfm_title\nTestNumberPolicy\npfm_type\ninteger\n'); + }); +}); diff --git a/build/lib/test/objectPolicy.test.js b/build/lib/test/objectPolicy.test.js new file mode 100644 index 00000000000..1c25d52cf61 --- /dev/null +++ b/build/lib/test/objectPolicy.test.js @@ -0,0 +1,118 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const assert_1 = __importDefault(require("assert")); +const objectPolicy_js_1 = require("../policies/objectPolicy.js"); +const types_js_1 = require("../policies/types.js"); +suite('ObjectPolicy', () => { + const mockCategory = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + const mockPolicy = { + key: 'test.object.policy', + name: 'TestObjectPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'object', + localization: { + description: { key: 'test.policy.description', value: 'Test policy description' } + } + }; + test('should create ObjectPolicy from factory method', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + assert_1.default.strictEqual(policy.name, 'TestObjectPolicy'); + assert_1.default.strictEqual(policy.minimumVersion, '1.0'); + assert_1.default.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert_1.default.strictEqual(policy.category.name.value, mockCategory.name.value); + assert_1.default.strictEqual(policy.type, types_js_1.PolicyType.Object); + }); + test('should render ADMX elements correctly', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admx = policy.renderADMX('TestKey'); + assert_1.default.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\t', + '' + ]); + }); + test('should render ADML strings correctly', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admlStrings = policy.renderADMLStrings(); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestObjectPolicy', + 'Test policy description' + ]); + }); + test('should render ADML strings with translations', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated description' + } + }; + const admlStrings = policy.renderADMLStrings(translations); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestObjectPolicy', + 'Translated description' + ]); + }); + test('should render ADML presentation correctly', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const presentation = policy.renderADMLPresentation(); + assert_1.default.strictEqual(presentation, ''); + }); + test('should render profile value correctly', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profileValue = policy.renderProfileValue(); + assert_1.default.strictEqual(profileValue, ''); + }); + test('should render profile correctly', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profile = policy.renderProfile(); + assert_1.default.strictEqual(profile.length, 2); + assert_1.default.strictEqual(profile[0], 'TestObjectPolicy'); + assert_1.default.strictEqual(profile[1], ''); + }); + test('should render profile manifest value correctly', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifestValue = policy.renderProfileManifestValue(); + assert_1.default.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTest policy description\npfm_name\nTestObjectPolicy\npfm_title\nTestObjectPolicy\npfm_type\nstring\n'); + }); + test('should render profile manifest value with translations', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + const manifestValue = policy.renderProfileManifestValue(translations); + assert_1.default.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTranslated manifest description\npfm_name\nTestObjectPolicy\npfm_title\nTestObjectPolicy\npfm_type\nstring\n'); + }); + test('should render profile manifest correctly', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifest = policy.renderProfileManifest(); + assert_1.default.strictEqual(manifest, '\npfm_default\n\npfm_description\nTest policy description\npfm_name\nTestObjectPolicy\npfm_title\nTestObjectPolicy\npfm_type\nstring\n\n'); + }); +}); +//# sourceMappingURL=objectPolicy.test.js.map \ No newline at end of file diff --git a/build/lib/test/objectPolicy.test.ts b/build/lib/test/objectPolicy.test.ts new file mode 100644 index 00000000000..a4c2638a52f --- /dev/null +++ b/build/lib/test/objectPolicy.test.ts @@ -0,0 +1,156 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { ObjectPolicy } from '../policies/objectPolicy.js'; +import { LanguageTranslations, PolicyType } from '../policies/types.js'; +import { CategoryDto, PolicyDto } from '../policies/policyDto.js'; + +suite('ObjectPolicy', () => { + const mockCategory: CategoryDto = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + + const mockPolicy: PolicyDto = { + key: 'test.object.policy', + name: 'TestObjectPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'object', + localization: { + description: { key: 'test.policy.description', value: 'Test policy description' } + } + }; + + test('should create ObjectPolicy from factory method', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + assert.strictEqual(policy.name, 'TestObjectPolicy'); + assert.strictEqual(policy.minimumVersion, '1.0'); + assert.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert.strictEqual(policy.category.name.value, mockCategory.name.value); + assert.strictEqual(policy.type, PolicyType.Object); + }); + + test('should render ADMX elements correctly', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admx = policy.renderADMX('TestKey'); + + assert.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\t', + '' + ]); + }); + + test('should render ADML strings correctly', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admlStrings = policy.renderADMLStrings(); + + assert.deepStrictEqual(admlStrings, [ + 'TestObjectPolicy', + 'Test policy description' + ]); + }); + + test('should render ADML strings with translations', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated description' + } + }; + + const admlStrings = policy.renderADMLStrings(translations); + + assert.deepStrictEqual(admlStrings, [ + 'TestObjectPolicy', + 'Translated description' + ]); + }); + + test('should render ADML presentation correctly', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const presentation = policy.renderADMLPresentation(); + + assert.strictEqual(presentation, ''); + }); + + test('should render profile value correctly', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profileValue = policy.renderProfileValue(); + + assert.strictEqual(profileValue, ''); + }); + + test('should render profile correctly', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profile = policy.renderProfile(); + + assert.strictEqual(profile.length, 2); + assert.strictEqual(profile[0], 'TestObjectPolicy'); + assert.strictEqual(profile[1], ''); + }); + + test('should render profile manifest value correctly', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifestValue = policy.renderProfileManifestValue(); + + assert.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTest policy description\npfm_name\nTestObjectPolicy\npfm_title\nTestObjectPolicy\npfm_type\nstring\n'); + }); + + test('should render profile manifest value with translations', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + + const manifestValue = policy.renderProfileManifestValue(translations); + + assert.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTranslated manifest description\npfm_name\nTestObjectPolicy\npfm_title\nTestObjectPolicy\npfm_type\nstring\n'); + }); + + test('should render profile manifest correctly', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifest = policy.renderProfileManifest(); + + assert.strictEqual(manifest, '\npfm_default\n\npfm_description\nTest policy description\npfm_name\nTestObjectPolicy\npfm_title\nTestObjectPolicy\npfm_type\nstring\n\n'); + }); +}); diff --git a/build/lib/test/policyConversion.test.js b/build/lib/test/policyConversion.test.js new file mode 100644 index 00000000000..0f61c856f04 --- /dev/null +++ b/build/lib/test/policyConversion.test.js @@ -0,0 +1,455 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const assert_1 = __importDefault(require("assert")); +const fs_1 = require("fs"); +const path_1 = __importDefault(require("path")); +const booleanPolicy_1 = require("../policies/booleanPolicy"); +const numberPolicy_1 = require("../policies/numberPolicy"); +const objectPolicy_1 = require("../policies/objectPolicy"); +const stringEnumPolicy_1 = require("../policies/stringEnumPolicy"); +const stringPolicy_1 = require("../policies/stringPolicy"); +const render_1 = require("../policies/render"); +const PolicyTypes = [ + booleanPolicy_1.BooleanPolicy, + numberPolicy_1.NumberPolicy, + stringEnumPolicy_1.StringEnumPolicy, + stringPolicy_1.StringPolicy, + objectPolicy_1.ObjectPolicy +]; +function parsePolicies(policyData) { + const categories = new Map(); + for (const category of policyData.categories) { + categories.set(category.key, category); + } + const policies = []; + for (const policy of policyData.policies) { + const category = categories.get(policy.category); + if (!category) { + throw new Error(`Unknown category: ${policy.category}`); + } + let result; + for (const policyType of PolicyTypes) { + if (result = policyType.from(category, policy)) { + break; + } + } + if (!result) { + throw new Error(`Unsupported policy type: ${policy.type} for policy ${policy.name}`); + } + policies.push(result); + } + // Sort policies first by category name, then by policy name + policies.sort((a, b) => { + const categoryCompare = a.category.name.value.localeCompare(b.category.name.value); + if (categoryCompare !== 0) { + return categoryCompare; + } + return a.name.localeCompare(b.name); + }); + return policies; +} +/** + * This is a snapshot of the data taken on Oct. 20 2025 as part of the + * policy refactor effort. Let's make sure that nothing has regressed. + */ +const policies = { + categories: [ + { + key: 'Extensions', + name: { + key: 'extensionsConfigurationTitle', + value: 'Extensions' + } + }, + { + key: 'IntegratedTerminal', + name: { + key: 'terminalIntegratedConfigurationTitle', + value: 'Integrated Terminal' + } + }, + { + key: 'InteractiveSession', + name: { + key: 'interactiveSessionConfigurationTitle', + value: 'Chat' + } + }, + { + key: 'Telemetry', + name: { + key: 'telemetryConfigurationTitle', + value: 'Telemetry' + } + }, + { + key: 'Update', + name: { + key: 'updateConfigurationTitle', + value: 'Update' + } + } + ], + policies: [ + { + key: 'chat.mcp.gallery.serviceUrl', + name: 'McpGalleryServiceUrl', + category: 'InteractiveSession', + minimumVersion: '1.101', + localization: { + description: { + key: 'mcp.gallery.serviceUrl', + value: 'Configure the MCP Gallery service URL to connect to' + } + }, + type: 'string', + default: '' + }, + { + key: 'extensions.gallery.serviceUrl', + name: 'ExtensionGalleryServiceUrl', + category: 'Extensions', + minimumVersion: '1.99', + localization: { + description: { + key: 'extensions.gallery.serviceUrl', + value: 'Configure the Marketplace service URL to connect to' + } + }, + type: 'string', + default: '' + }, + { + key: 'extensions.allowed', + name: 'AllowedExtensions', + category: 'Extensions', + minimumVersion: '1.96', + localization: { + description: { + key: 'extensions.allowed.policy', + value: 'Specify a list of extensions that are allowed to use. This helps maintain a secure and consistent development environment by restricting the use of unauthorized extensions. More information: https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions' + } + }, + type: 'object', + default: '*' + }, + { + key: 'chat.tools.global.autoApprove', + name: 'ChatToolsAutoApprove', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'autoApprove2.description', + value: 'Global auto approve also known as "YOLO mode" disables manual approval completely for all tools in all workspaces, allowing the agent to act fully autonomously. This is extremely dangerous and is *never* recommended, even containerized environments like Codespaces and Dev Containers have user keys forwarded into the container that could be compromised.\n\nThis feature disables critical security protections and makes it much easier for an attacker to compromise the machine.' + } + }, + type: 'boolean', + default: false + }, + { + key: 'chat.mcp.access', + name: 'ChatMCP', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'chat.mcp.access', + value: 'Controls access to installed Model Context Protocol servers.' + }, + enumDescriptions: [ + { + key: 'chat.mcp.access.none', + value: 'No access to MCP servers.' + }, + { + key: 'chat.mcp.access.registry', + value: 'Allows access to MCP servers installed from the registry that VS Code is connected to.' + }, + { + key: 'chat.mcp.access.any', + value: 'Allow access to any installed MCP server.' + } + ] + }, + type: 'string', + default: 'all', + enum: [ + 'none', + 'registry', + 'all' + ] + }, + { + key: 'chat.extensionTools.enabled', + name: 'ChatAgentExtensionTools', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'chat.extensionToolsEnabled', + value: 'Enable using tools contributed by third-party extensions.' + } + }, + type: 'boolean', + default: true + }, + { + key: 'chat.agent.enabled', + name: 'ChatAgentMode', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'chat.agent.enabled.description', + value: 'Enable agent mode for chat. When this is enabled, agent mode can be activated via the dropdown in the view.' + } + }, + type: 'boolean', + default: true + }, + { + key: 'chat.promptFiles', + name: 'ChatPromptFiles', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'chat.promptFiles.policy', + value: 'Enables reusable prompt and instruction files in Chat sessions.' + } + }, + type: 'boolean', + default: true + }, + { + key: 'chat.tools.terminal.enableAutoApprove', + name: 'ChatToolsTerminalEnableAutoApprove', + category: 'IntegratedTerminal', + minimumVersion: '1.104', + localization: { + description: { + key: 'autoApproveMode.description', + value: 'Controls whether to allow auto approval in the run in terminal tool.' + } + }, + type: 'boolean', + default: true + }, + { + key: 'update.mode', + name: 'UpdateMode', + category: 'Update', + minimumVersion: '1.67', + localization: { + description: { + key: 'updateMode', + value: 'Configure whether you receive automatic updates. Requires a restart after change. The updates are fetched from a Microsoft online service.' + }, + enumDescriptions: [ + { + key: 'none', + value: 'Disable updates.' + }, + { + key: 'manual', + value: 'Disable automatic background update checks. Updates will be available if you manually check for updates.' + }, + { + key: 'start', + value: 'Check for updates only on startup. Disable automatic background update checks.' + }, + { + key: 'default', + value: 'Enable automatic update checks. Code will check for updates automatically and periodically.' + } + ] + }, + type: 'string', + default: 'default', + enum: [ + 'none', + 'manual', + 'start', + 'default' + ] + }, + { + key: 'telemetry.telemetryLevel', + name: 'TelemetryLevel', + category: 'Telemetry', + minimumVersion: '1.99', + localization: { + description: { + key: 'telemetry.telemetryLevel.policyDescription', + value: 'Controls the level of telemetry.' + }, + enumDescriptions: [ + { + key: 'telemetry.telemetryLevel.default', + value: 'Sends usage data, errors, and crash reports.' + }, + { + key: 'telemetry.telemetryLevel.error', + value: 'Sends general error telemetry and crash reports.' + }, + { + key: 'telemetry.telemetryLevel.crash', + value: 'Sends OS level crash reports.' + }, + { + key: 'telemetry.telemetryLevel.off', + value: 'Disables all product telemetry.' + } + ] + }, + type: 'string', + default: 'all', + enum: [ + 'all', + 'error', + 'crash', + 'off' + ] + }, + { + key: 'telemetry.feedback.enabled', + name: 'EnableFeedback', + category: 'Telemetry', + minimumVersion: '1.99', + localization: { + description: { + key: 'telemetry.feedback.enabled', + value: 'Enable feedback mechanisms such as the issue reporter, surveys, and other feedback options.' + } + }, + type: 'boolean', + default: true + } + ] +}; +const mockProduct = { + nameLong: 'Code - OSS', + darwinBundleIdentifier: 'com.visualstudio.code.oss', + darwinProfilePayloadUUID: 'CF808BE7-53F3-46C6-A7E2-7EDB98A5E959', + darwinProfileUUID: '47827DD9-4734-49A0-AF80-7E19B11495CC', + win32RegValueName: 'CodeOSS' +}; +const frenchTranslations = [ + { + languageId: 'fr-fr', + languageTranslations: { + '': { + 'interactiveSessionConfigurationTitle': 'Session interactive', + 'extensionsConfigurationTitle': 'Extensions', + 'terminalIntegratedConfigurationTitle': 'Terminal intégré', + 'telemetryConfigurationTitle': 'Télémétrie', + 'updateConfigurationTitle': 'Mettre à jour', + 'chat.extensionToolsEnabled': 'Autorisez l’utilisation d’outils fournis par des extensions tierces.', + 'chat.agent.enabled.description': 'Activez le mode Assistant pour la conversation. Lorsque cette option est activée, le mode Assistant peut être activé via la liste déroulante de la vue.', + 'chat.mcp.access': 'Contrôle l’accès aux serveurs de protocole de contexte du modèle.', + 'chat.mcp.access.none': 'Aucun accès aux serveurs MCP.', + 'chat.mcp.access.registry': `Autorise l’accès aux serveurs MCP installés à partir du registre auquel VS Code est connecté.`, + 'chat.mcp.access.any': 'Autorisez l’accès à tout serveur MCP installé.', + 'chat.promptFiles.policy': 'Active les fichiers d’instruction et de requête réutilisables dans les sessions Conversation.', + 'autoApprove2.description': `L’approbation automatique globale, également appelée « mode YOLO », désactive complètement l’approbation manuelle pour tous les outils dans tous les espaces de travail, permettant à l’agent d’agir de manière totalement autonome. Ceci est extrêmement dangereux et est *jamais* recommandé, même dans des environnements conteneurisés comme [Codespaces](https://github.com/features/codespaces) et [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), où des clés utilisateur sont transférées dans le conteneur et pourraient être compromises. + +Cette fonctionnalité désactive [les protections de sécurité critiques](https://code.visualstudio.com/docs/copilot/security) et facilite considérablement la compromission de la machine par un attaquant.`, + 'mcp.gallery.serviceUrl': 'Configurer l’URL du service de la galerie MCP à laquelle se connecter', + 'extensions.allowed.policy': 'Spécifiez une liste d’extensions autorisées. Cela permet de maintenir un environnement de développement sécurisé et cohérent en limitant l’utilisation d’extensions non autorisées. Plus d’informations : https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions', + 'extensions.gallery.serviceUrl': 'Configurer l’URL du service Place de marché à laquelle se connecter', + 'autoApproveMode.description': 'Contrôle s’il faut autoriser l’approbation automatique lors de l’exécution dans l’outil terminal.', + 'telemetry.feedback.enabled': 'Activez les mécanismes de commentaires tels que le système de rapport de problèmes, les sondages et autres options de commentaires.', + 'telemetry.telemetryLevel.policyDescription': 'Contrôle le niveau de télémétrie.', + 'telemetry.telemetryLevel.default': `Envoie les données d'utilisation, les erreurs et les rapports d'erreur.`, + 'telemetry.telemetryLevel.error': `Envoie la télémétrie d'erreur générale et les rapports de plantage.`, + 'telemetry.telemetryLevel.crash': `Envoie des rapports de plantage au niveau du système d'exploitation.`, + 'telemetry.telemetryLevel.off': 'Désactive toutes les données de télémétrie du produit.', + 'updateMode': `Choisissez si vous voulez recevoir des mises à jour automatiques. Nécessite un redémarrage après le changement. Les mises à jour sont récupérées auprès d'un service en ligne Microsoft.`, + 'none': 'Aucun', + 'manual': 'Désactivez la recherche de mises à jour automatique en arrière-plan. Les mises à jour sont disponibles si vous les rechercher manuellement.', + 'start': 'Démarrer', + 'default': 'Système' + } + } + } +]; +suite('Policy E2E conversion', () => { + test('should render macOS policy profile from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = (0, render_1.renderMacOSPolicy)(mockProduct, parsedPolicies, []); + // Load the expected fixture file + const fixturePath = path_1.default.join(__dirname, 'fixtures', 'policies', 'darwin', 'com.visualstudio.code.oss.mobileconfig'); + const expectedContent = await fs_1.promises.readFile(fixturePath, 'utf-8'); + // Compare the rendered profile with the fixture + assert_1.default.strictEqual(result.profile, expectedContent, 'macOS policy profile should match the fixture'); + }); + test('should render macOS manifest from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = (0, render_1.renderMacOSPolicy)(mockProduct, parsedPolicies, []); + // Load the expected fixture file + const fixturePath = path_1.default.join(__dirname, 'fixtures', 'policies', 'darwin', 'en-us', 'com.visualstudio.code.oss.plist'); + const expectedContent = await fs_1.promises.readFile(fixturePath, 'utf-8'); + // Find the en-us manifest + const enUsManifest = result.manifests.find(m => m.languageId === 'en-us'); + assert_1.default.ok(enUsManifest, 'en-us manifest should exist'); + // Compare the rendered manifest with the fixture, ignoring the timestamp + // The pfm_last_modified field contains a timestamp that will differ each time + const normalizeTimestamp = (content) => content.replace(/.*?<\/date>/, 'TIMESTAMP'); + assert_1.default.strictEqual(normalizeTimestamp(enUsManifest.contents), normalizeTimestamp(expectedContent), 'macOS manifest should match the fixture (ignoring timestamp)'); + }); + test('should render Windows ADMX from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = (0, render_1.renderGP)(mockProduct, parsedPolicies, []); + // Load the expected fixture file + const fixturePath = path_1.default.join(__dirname, 'fixtures', 'policies', 'win32', 'CodeOSS.admx'); + const expectedContent = await fs_1.promises.readFile(fixturePath, 'utf-8'); + // Compare the rendered ADMX with the fixture + assert_1.default.strictEqual(result.admx, expectedContent, 'Windows ADMX should match the fixture'); + }); + test('should render Windows ADML from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = (0, render_1.renderGP)(mockProduct, parsedPolicies, []); + // Load the expected fixture file + const fixturePath = path_1.default.join(__dirname, 'fixtures', 'policies', 'win32', 'en-us', 'CodeOSS.adml'); + const expectedContent = await fs_1.promises.readFile(fixturePath, 'utf-8'); + // Find the en-us ADML + const enUsAdml = result.adml.find(a => a.languageId === 'en-us'); + assert_1.default.ok(enUsAdml, 'en-us ADML should exist'); + // Compare the rendered ADML with the fixture + assert_1.default.strictEqual(enUsAdml.contents, expectedContent, 'Windows ADML should match the fixture'); + }); + test('should render macOS manifest with fr-fr locale', async () => { + const parsedPolicies = parsePolicies(policies); + const result = (0, render_1.renderMacOSPolicy)(mockProduct, parsedPolicies, frenchTranslations); + // Load the expected fixture file + const fixturePath = path_1.default.join(__dirname, 'fixtures', 'policies', 'darwin', 'fr-fr', 'com.visualstudio.code.oss.plist'); + const expectedContent = await fs_1.promises.readFile(fixturePath, 'utf-8'); + // Find the fr-fr manifest + const frFrManifest = result.manifests.find(m => m.languageId === 'fr-fr'); + assert_1.default.ok(frFrManifest, 'fr-fr manifest should exist'); + // Compare the rendered manifest with the fixture, ignoring the timestamp + const normalizeTimestamp = (content) => content.replace(/.*?<\/date>/, 'TIMESTAMP'); + assert_1.default.strictEqual(normalizeTimestamp(frFrManifest.contents), normalizeTimestamp(expectedContent), 'macOS fr-fr manifest should match the fixture (ignoring timestamp)'); + }); + test('should render Windows ADML with fr-fr locale', async () => { + const parsedPolicies = parsePolicies(policies); + const result = (0, render_1.renderGP)(mockProduct, parsedPolicies, frenchTranslations); + // Load the expected fixture file + const fixturePath = path_1.default.join(__dirname, 'fixtures', 'policies', 'win32', 'fr-fr', 'CodeOSS.adml'); + const expectedContent = await fs_1.promises.readFile(fixturePath, 'utf-8'); + // Find the fr-fr ADML + const frFrAdml = result.adml.find(a => a.languageId === 'fr-fr'); + assert_1.default.ok(frFrAdml, 'fr-fr ADML should exist'); + // Compare the rendered ADML with the fixture + assert_1.default.strictEqual(frFrAdml.contents, expectedContent, 'Windows fr-fr ADML should match the fixture'); + }); +}); +//# sourceMappingURL=policyConversion.test.js.map \ No newline at end of file diff --git a/build/lib/test/policyConversion.test.ts b/build/lib/test/policyConversion.test.ts new file mode 100644 index 00000000000..3be9fd8c10d --- /dev/null +++ b/build/lib/test/policyConversion.test.ts @@ -0,0 +1,495 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { promises as fs } from 'fs'; +import path from 'path'; +import { ExportedPolicyDataDto, CategoryDto } from '../policies/policyDto'; +import { BooleanPolicy } from '../policies/booleanPolicy'; +import { NumberPolicy } from '../policies/numberPolicy'; +import { ObjectPolicy } from '../policies/objectPolicy'; +import { StringEnumPolicy } from '../policies/stringEnumPolicy'; +import { StringPolicy } from '../policies/stringPolicy'; +import { Policy, ProductJson } from '../policies/types'; +import { renderGP, renderMacOSPolicy } from '../policies/render'; + +const PolicyTypes = [ + BooleanPolicy, + NumberPolicy, + StringEnumPolicy, + StringPolicy, + ObjectPolicy +]; + +function parsePolicies(policyData: ExportedPolicyDataDto): Policy[] { + const categories = new Map(); + for (const category of policyData.categories) { + categories.set(category.key, category); + } + + const policies: Policy[] = []; + for (const policy of policyData.policies) { + const category = categories.get(policy.category); + if (!category) { + throw new Error(`Unknown category: ${policy.category}`); + } + + let result: Policy | undefined; + for (const policyType of PolicyTypes) { + if (result = policyType.from(category, policy)) { + break; + } + } + + if (!result) { + throw new Error(`Unsupported policy type: ${policy.type} for policy ${policy.name}`); + } + + policies.push(result); + } + + // Sort policies first by category name, then by policy name + policies.sort((a, b) => { + const categoryCompare = a.category.name.value.localeCompare(b.category.name.value); + if (categoryCompare !== 0) { + return categoryCompare; + } + return a.name.localeCompare(b.name); + }); + + return policies; +} + +/** + * This is a snapshot of the data taken on Oct. 20 2025 as part of the + * policy refactor effort. Let's make sure that nothing has regressed. + */ +const policies: ExportedPolicyDataDto = { + categories: [ + { + key: 'Extensions', + name: { + key: 'extensionsConfigurationTitle', + value: 'Extensions' + } + }, + { + key: 'IntegratedTerminal', + name: { + key: 'terminalIntegratedConfigurationTitle', + value: 'Integrated Terminal' + } + }, + { + key: 'InteractiveSession', + name: { + key: 'interactiveSessionConfigurationTitle', + value: 'Chat' + } + }, + { + key: 'Telemetry', + name: { + key: 'telemetryConfigurationTitle', + value: 'Telemetry' + } + }, + { + key: 'Update', + name: { + key: 'updateConfigurationTitle', + value: 'Update' + } + } + ], + policies: [ + { + key: 'chat.mcp.gallery.serviceUrl', + name: 'McpGalleryServiceUrl', + category: 'InteractiveSession', + minimumVersion: '1.101', + localization: { + description: { + key: 'mcp.gallery.serviceUrl', + value: 'Configure the MCP Gallery service URL to connect to' + } + }, + type: 'string', + default: '' + }, + { + key: 'extensions.gallery.serviceUrl', + name: 'ExtensionGalleryServiceUrl', + category: 'Extensions', + minimumVersion: '1.99', + localization: { + description: { + key: 'extensions.gallery.serviceUrl', + value: 'Configure the Marketplace service URL to connect to' + } + }, + type: 'string', + default: '' + }, + { + key: 'extensions.allowed', + name: 'AllowedExtensions', + category: 'Extensions', + minimumVersion: '1.96', + localization: { + description: { + key: 'extensions.allowed.policy', + value: 'Specify a list of extensions that are allowed to use. This helps maintain a secure and consistent development environment by restricting the use of unauthorized extensions. More information: https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions' + } + }, + type: 'object', + default: '*' + }, + { + key: 'chat.tools.global.autoApprove', + name: 'ChatToolsAutoApprove', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'autoApprove2.description', + value: 'Global auto approve also known as "YOLO mode" disables manual approval completely for all tools in all workspaces, allowing the agent to act fully autonomously. This is extremely dangerous and is *never* recommended, even containerized environments like Codespaces and Dev Containers have user keys forwarded into the container that could be compromised.\n\nThis feature disables critical security protections and makes it much easier for an attacker to compromise the machine.' + } + }, + type: 'boolean', + default: false + }, + { + key: 'chat.mcp.access', + name: 'ChatMCP', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'chat.mcp.access', + value: 'Controls access to installed Model Context Protocol servers.' + }, + enumDescriptions: [ + { + key: 'chat.mcp.access.none', + value: 'No access to MCP servers.' + }, + { + key: 'chat.mcp.access.registry', + value: 'Allows access to MCP servers installed from the registry that VS Code is connected to.' + }, + { + key: 'chat.mcp.access.any', + value: 'Allow access to any installed MCP server.' + } + ] + }, + type: 'string', + default: 'all', + enum: [ + 'none', + 'registry', + 'all' + ] + }, + { + key: 'chat.extensionTools.enabled', + name: 'ChatAgentExtensionTools', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'chat.extensionToolsEnabled', + value: 'Enable using tools contributed by third-party extensions.' + } + }, + type: 'boolean', + default: true + }, + { + key: 'chat.agent.enabled', + name: 'ChatAgentMode', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'chat.agent.enabled.description', + value: 'Enable agent mode for chat. When this is enabled, agent mode can be activated via the dropdown in the view.' + } + }, + type: 'boolean', + default: true + }, + { + key: 'chat.promptFiles', + name: 'ChatPromptFiles', + category: 'InteractiveSession', + minimumVersion: '1.99', + localization: { + description: { + key: 'chat.promptFiles.policy', + value: 'Enables reusable prompt and instruction files in Chat sessions.' + } + }, + type: 'boolean', + default: true + }, + { + key: 'chat.tools.terminal.enableAutoApprove', + name: 'ChatToolsTerminalEnableAutoApprove', + category: 'IntegratedTerminal', + minimumVersion: '1.104', + localization: { + description: { + key: 'autoApproveMode.description', + value: 'Controls whether to allow auto approval in the run in terminal tool.' + } + }, + type: 'boolean', + default: true + }, + { + key: 'update.mode', + name: 'UpdateMode', + category: 'Update', + minimumVersion: '1.67', + localization: { + description: { + key: 'updateMode', + value: 'Configure whether you receive automatic updates. Requires a restart after change. The updates are fetched from a Microsoft online service.' + }, + enumDescriptions: [ + { + key: 'none', + value: 'Disable updates.' + }, + { + key: 'manual', + value: 'Disable automatic background update checks. Updates will be available if you manually check for updates.' + }, + { + key: 'start', + value: 'Check for updates only on startup. Disable automatic background update checks.' + }, + { + key: 'default', + value: 'Enable automatic update checks. Code will check for updates automatically and periodically.' + } + ] + }, + type: 'string', + default: 'default', + enum: [ + 'none', + 'manual', + 'start', + 'default' + ] + }, + { + key: 'telemetry.telemetryLevel', + name: 'TelemetryLevel', + category: 'Telemetry', + minimumVersion: '1.99', + localization: { + description: { + key: 'telemetry.telemetryLevel.policyDescription', + value: 'Controls the level of telemetry.' + }, + enumDescriptions: [ + { + key: 'telemetry.telemetryLevel.default', + value: 'Sends usage data, errors, and crash reports.' + }, + { + key: 'telemetry.telemetryLevel.error', + value: 'Sends general error telemetry and crash reports.' + }, + { + key: 'telemetry.telemetryLevel.crash', + value: 'Sends OS level crash reports.' + }, + { + key: 'telemetry.telemetryLevel.off', + value: 'Disables all product telemetry.' + } + ] + }, + type: 'string', + default: 'all', + enum: [ + 'all', + 'error', + 'crash', + 'off' + ] + }, + { + key: 'telemetry.feedback.enabled', + name: 'EnableFeedback', + category: 'Telemetry', + minimumVersion: '1.99', + localization: { + description: { + key: 'telemetry.feedback.enabled', + value: 'Enable feedback mechanisms such as the issue reporter, surveys, and other feedback options.' + } + }, + type: 'boolean', + default: true + } + ] +}; + +const mockProduct: ProductJson = { + nameLong: 'Code - OSS', + darwinBundleIdentifier: 'com.visualstudio.code.oss', + darwinProfilePayloadUUID: 'CF808BE7-53F3-46C6-A7E2-7EDB98A5E959', + darwinProfileUUID: '47827DD9-4734-49A0-AF80-7E19B11495CC', + win32RegValueName: 'CodeOSS' +}; + +const frenchTranslations = [ + { + languageId: 'fr-fr', + languageTranslations: { + '': { + 'interactiveSessionConfigurationTitle': 'Session interactive', + 'extensionsConfigurationTitle': 'Extensions', + 'terminalIntegratedConfigurationTitle': 'Terminal intégré', + 'telemetryConfigurationTitle': 'Télémétrie', + 'updateConfigurationTitle': 'Mettre à jour', + 'chat.extensionToolsEnabled': 'Autorisez l’utilisation d’outils fournis par des extensions tierces.', + 'chat.agent.enabled.description': 'Activez le mode Assistant pour la conversation. Lorsque cette option est activée, le mode Assistant peut être activé via la liste déroulante de la vue.', + 'chat.mcp.access': 'Contrôle l’accès aux serveurs de protocole de contexte du modèle.', + 'chat.mcp.access.none': 'Aucun accès aux serveurs MCP.', + 'chat.mcp.access.registry': `Autorise l’accès aux serveurs MCP installés à partir du registre auquel VS Code est connecté.`, + 'chat.mcp.access.any': 'Autorisez l’accès à tout serveur MCP installé.', + 'chat.promptFiles.policy': 'Active les fichiers d’instruction et de requête réutilisables dans les sessions Conversation.', + 'autoApprove2.description': `L’approbation automatique globale, également appelée « mode YOLO », désactive complètement l’approbation manuelle pour tous les outils dans tous les espaces de travail, permettant à l’agent d’agir de manière totalement autonome. Ceci est extrêmement dangereux et est *jamais* recommandé, même dans des environnements conteneurisés comme [Codespaces](https://github.com/features/codespaces) et [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), où des clés utilisateur sont transférées dans le conteneur et pourraient être compromises. + +Cette fonctionnalité désactive [les protections de sécurité critiques](https://code.visualstudio.com/docs/copilot/security) et facilite considérablement la compromission de la machine par un attaquant.`, + 'mcp.gallery.serviceUrl': 'Configurer l’URL du service de la galerie MCP à laquelle se connecter', + 'extensions.allowed.policy': 'Spécifiez une liste d’extensions autorisées. Cela permet de maintenir un environnement de développement sécurisé et cohérent en limitant l’utilisation d’extensions non autorisées. Plus d’informations : https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions', + 'extensions.gallery.serviceUrl': 'Configurer l’URL du service Place de marché à laquelle se connecter', + 'autoApproveMode.description': 'Contrôle s’il faut autoriser l’approbation automatique lors de l’exécution dans l’outil terminal.', + 'telemetry.feedback.enabled': 'Activez les mécanismes de commentaires tels que le système de rapport de problèmes, les sondages et autres options de commentaires.', + 'telemetry.telemetryLevel.policyDescription': 'Contrôle le niveau de télémétrie.', + 'telemetry.telemetryLevel.default': `Envoie les données d'utilisation, les erreurs et les rapports d'erreur.`, + 'telemetry.telemetryLevel.error': `Envoie la télémétrie d'erreur générale et les rapports de plantage.`, + 'telemetry.telemetryLevel.crash': `Envoie des rapports de plantage au niveau du système d'exploitation.`, + 'telemetry.telemetryLevel.off': 'Désactive toutes les données de télémétrie du produit.', + 'updateMode': `Choisissez si vous voulez recevoir des mises à jour automatiques. Nécessite un redémarrage après le changement. Les mises à jour sont récupérées auprès d'un service en ligne Microsoft.`, + 'none': 'Aucun', + 'manual': 'Désactivez la recherche de mises à jour automatique en arrière-plan. Les mises à jour sont disponibles si vous les rechercher manuellement.', + 'start': 'Démarrer', + 'default': 'Système' + } + } + } +]; + +suite('Policy E2E conversion', () => { + + test('should render macOS policy profile from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = renderMacOSPolicy(mockProduct, parsedPolicies, []); + + // Load the expected fixture file + const fixturePath = path.join(__dirname, 'fixtures', 'policies', 'darwin', 'com.visualstudio.code.oss.mobileconfig'); + const expectedContent = await fs.readFile(fixturePath, 'utf-8'); + + // Compare the rendered profile with the fixture + assert.strictEqual(result.profile, expectedContent, 'macOS policy profile should match the fixture'); + }); + + test('should render macOS manifest from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = renderMacOSPolicy(mockProduct, parsedPolicies, []); + + // Load the expected fixture file + const fixturePath = path.join(__dirname, 'fixtures', 'policies', 'darwin', 'en-us', 'com.visualstudio.code.oss.plist'); + const expectedContent = await fs.readFile(fixturePath, 'utf-8'); + + // Find the en-us manifest + const enUsManifest = result.manifests.find(m => m.languageId === 'en-us'); + assert.ok(enUsManifest, 'en-us manifest should exist'); + + // Compare the rendered manifest with the fixture, ignoring the timestamp + // The pfm_last_modified field contains a timestamp that will differ each time + const normalizeTimestamp = (content: string) => content.replace(/.*?<\/date>/, 'TIMESTAMP'); + assert.strictEqual( + normalizeTimestamp(enUsManifest.contents), + normalizeTimestamp(expectedContent), + 'macOS manifest should match the fixture (ignoring timestamp)' + ); + }); + + test('should render Windows ADMX from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = renderGP(mockProduct, parsedPolicies, []); + + // Load the expected fixture file + const fixturePath = path.join(__dirname, 'fixtures', 'policies', 'win32', 'CodeOSS.admx'); + const expectedContent = await fs.readFile(fixturePath, 'utf-8'); + + // Compare the rendered ADMX with the fixture + assert.strictEqual(result.admx, expectedContent, 'Windows ADMX should match the fixture'); + }); + + test('should render Windows ADML from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = renderGP(mockProduct, parsedPolicies, []); + + // Load the expected fixture file + const fixturePath = path.join(__dirname, 'fixtures', 'policies', 'win32', 'en-us', 'CodeOSS.adml'); + const expectedContent = await fs.readFile(fixturePath, 'utf-8'); + + // Find the en-us ADML + const enUsAdml = result.adml.find(a => a.languageId === 'en-us'); + assert.ok(enUsAdml, 'en-us ADML should exist'); + + // Compare the rendered ADML with the fixture + assert.strictEqual(enUsAdml.contents, expectedContent, 'Windows ADML should match the fixture'); + }); + + test('should render macOS manifest with fr-fr locale', async () => { + const parsedPolicies = parsePolicies(policies); + const result = renderMacOSPolicy(mockProduct, parsedPolicies, frenchTranslations); + + // Load the expected fixture file + const fixturePath = path.join(__dirname, 'fixtures', 'policies', 'darwin', 'fr-fr', 'com.visualstudio.code.oss.plist'); + const expectedContent = await fs.readFile(fixturePath, 'utf-8'); + + // Find the fr-fr manifest + const frFrManifest = result.manifests.find(m => m.languageId === 'fr-fr'); + assert.ok(frFrManifest, 'fr-fr manifest should exist'); + + // Compare the rendered manifest with the fixture, ignoring the timestamp + const normalizeTimestamp = (content: string) => content.replace(/.*?<\/date>/, 'TIMESTAMP'); + assert.strictEqual( + normalizeTimestamp(frFrManifest.contents), + normalizeTimestamp(expectedContent), + 'macOS fr-fr manifest should match the fixture (ignoring timestamp)' + ); + }); + + test('should render Windows ADML with fr-fr locale', async () => { + const parsedPolicies = parsePolicies(policies); + const result = renderGP(mockProduct, parsedPolicies, frenchTranslations); + + // Load the expected fixture file + const fixturePath = path.join(__dirname, 'fixtures', 'policies', 'win32', 'fr-fr', 'CodeOSS.adml'); + const expectedContent = await fs.readFile(fixturePath, 'utf-8'); + + // Find the fr-fr ADML + const frFrAdml = result.adml.find(a => a.languageId === 'fr-fr'); + assert.ok(frFrAdml, 'fr-fr ADML should exist'); + + // Compare the rendered ADML with the fixture + assert.strictEqual(frFrAdml.contents, expectedContent, 'Windows fr-fr ADML should match the fixture'); + }); + +}); diff --git a/build/lib/test/render.test.js b/build/lib/test/render.test.js new file mode 100644 index 00000000000..005460c6204 --- /dev/null +++ b/build/lib/test/render.test.js @@ -0,0 +1,683 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const assert_1 = __importDefault(require("assert")); +const render_js_1 = require("../policies/render.js"); +const types_js_1 = require("../policies/types.js"); +suite('Render Functions', () => { + suite('renderADMLString', () => { + test('should render ADML string without translations', () => { + const nlsString = { + value: 'Test description', + nlsKey: 'test.description' + }; + const result = (0, render_js_1.renderADMLString)('TestPrefix', 'testModule', nlsString); + assert_1.default.strictEqual(result, 'Test description'); + }); + test('should replace dots with underscores in nls key', () => { + const nlsString = { + value: 'Test value', + nlsKey: 'my.test.nls.key' + }; + const result = (0, render_js_1.renderADMLString)('Prefix', 'testModule', nlsString); + assert_1.default.ok(result.includes('id="Prefix_my_test_nls_key"')); + }); + test('should use translation when available', () => { + const nlsString = { + value: 'Original value', + nlsKey: 'test.key' + }; + const translations = { + 'testModule': { + 'test.key': 'Translated value' + } + }; + const result = (0, render_js_1.renderADMLString)('TestPrefix', 'testModule', nlsString, translations); + assert_1.default.ok(result.includes('>Translated value')); + }); + test('should fallback to original value when translation not found', () => { + const nlsString = { + value: 'Original value', + nlsKey: 'test.key' + }; + const translations = { + 'testModule': { + 'other.key': 'Other translation' + } + }; + const result = (0, render_js_1.renderADMLString)('TestPrefix', 'testModule', nlsString, translations); + assert_1.default.ok(result.includes('>Original value')); + }); + }); + suite('renderProfileString', () => { + test('should render profile string without translations', () => { + const nlsString = { + value: 'Profile description', + nlsKey: 'profile.description' + }; + const result = (0, render_js_1.renderProfileString)('ProfilePrefix', 'testModule', nlsString); + assert_1.default.strictEqual(result, 'Profile description'); + }); + test('should use translation when available', () => { + const nlsString = { + value: 'Original profile value', + nlsKey: 'profile.key' + }; + const translations = { + 'testModule': { + 'profile.key': 'Translated profile value' + } + }; + const result = (0, render_js_1.renderProfileString)('ProfilePrefix', 'testModule', nlsString, translations); + assert_1.default.strictEqual(result, 'Translated profile value'); + }); + test('should fallback to original value when translation not found', () => { + const nlsString = { + value: 'Original profile value', + nlsKey: 'profile.key' + }; + const translations = { + 'testModule': { + 'other.key': 'Other translation' + } + }; + const result = (0, render_js_1.renderProfileString)('ProfilePrefix', 'testModule', nlsString, translations); + assert_1.default.strictEqual(result, 'Original profile value'); + }); + }); + suite('renderADMX', () => { + const mockCategory = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + const mockPolicy = { + name: 'TestPolicy', + type: types_js_1.PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.85', + renderADMX: (regKey) => [ + ``, + ` `, + `` + ], + renderADMLStrings: () => ['Test Policy'], + renderADMLPresentation: () => '', + renderProfile: () => ['TestPolicy', ''], + renderProfileManifest: () => 'pfm_nameTestPolicy' + }; + test('should render ADMX with correct XML structure', () => { + const result = (0, render_js_1.renderADMX)('VSCode', ['1.85'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('')); + assert_1.default.ok(result.includes('')); + }); + test('should include policy namespaces with regKey', () => { + const result = (0, render_js_1.renderADMX)('TestApp', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes(' { + const result = (0, render_js_1.renderADMX)('VSCode', ['1.85.0', '1.90.1'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('Supported_1_85_0')); + assert_1.default.ok(result.includes('Supported_1_90_1')); + assert_1.default.ok(!result.includes('Supported_1.85.0')); + }); + test('should include categories in correct structure', () => { + const result = (0, render_js_1.renderADMX)('VSCode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('')); + assert_1.default.ok(result.includes('')); + }); + test('should include policies section', () => { + const result = (0, render_js_1.renderADMX)('VSCode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('')); + assert_1.default.ok(result.includes('TestPolicy')); + assert_1.default.ok(result.includes('')); + }); + test('should handle multiple versions', () => { + const result = (0, render_js_1.renderADMX)('VSCode', ['1.0', '1.5', '2.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('Supported_1_0')); + assert_1.default.ok(result.includes('Supported_1_5')); + assert_1.default.ok(result.includes('Supported_2_0')); + }); + test('should handle multiple categories', () => { + const category1 = { moduleName: 'testModule', name: { value: 'Cat1', nlsKey: 'cat1' } }; + const category2 = { moduleName: 'testModule', name: { value: 'Cat2', nlsKey: 'cat2' } }; + const result = (0, render_js_1.renderADMX)('VSCode', ['1.0'], [category1, category2], [mockPolicy]); + assert_1.default.ok(result.includes('Category_cat1')); + assert_1.default.ok(result.includes('Category_cat2')); + }); + test('should handle multiple policies', () => { + const policy2 = { + name: 'TestPolicy2', + type: types_js_1.PolicyType.String, + category: mockCategory, + minimumVersion: '1.85', + renderADMX: (regKey) => [ + ``, + ` `, + `` + ], + renderADMLStrings: () => ['Test Policy 2'], + renderADMLPresentation: () => '', + renderProfile: () => ['TestPolicy2', ''], + renderProfileManifest: () => 'pfm_nameTestPolicy2' + }; + const result = (0, render_js_1.renderADMX)('VSCode', ['1.0'], [mockCategory], [mockPolicy, policy2]); + assert_1.default.ok(result.includes('TestPolicy')); + assert_1.default.ok(result.includes('TestPolicy2')); + }); + }); + suite('renderADML', () => { + const mockCategory = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + const mockPolicy = { + name: 'TestPolicy', + type: types_js_1.PolicyType.String, + category: mockCategory, + minimumVersion: '1.85', + renderADMX: () => [], + renderADMLStrings: (translations) => [ + `Test Policy ${translations?.['testModule']?.['test.policy'] || 'Default'}` + ], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '' + }; + test('should render ADML with correct XML structure', () => { + const result = (0, render_js_1.renderADML)('VS Code', ['1.85'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('')); + assert_1.default.ok(result.includes('')); + }); + test('should include application name', () => { + const result = (0, render_js_1.renderADML)('My Application', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('My Application')); + }); + test('should include supported versions with escaped greater-than', () => { + const result = (0, render_js_1.renderADML)('VS Code', ['1.85', '1.90'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('VS Code >= 1.85')); + assert_1.default.ok(result.includes('VS Code >= 1.90')); + }); + test('should include category strings', () => { + const result = (0, render_js_1.renderADML)('VS Code', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('Category_test_category')); + }); + test('should include policy strings', () => { + const result = (0, render_js_1.renderADML)('VS Code', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('TestPolicy')); + assert_1.default.ok(result.includes('Test Policy Default')); + }); + test('should include policy presentations', () => { + const result = (0, render_js_1.renderADML)('VS Code', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('')); + assert_1.default.ok(result.includes('')); + assert_1.default.ok(result.includes('')); + }); + test('should pass translations to policy strings', () => { + const translations = { + 'testModule': { + 'test.policy': 'Translated' + } + }; + const result = (0, render_js_1.renderADML)('VS Code', ['1.0'], [mockCategory], [mockPolicy], translations); + assert_1.default.ok(result.includes('Test Policy Translated')); + }); + test('should handle multiple categories', () => { + const category1 = { moduleName: 'testModule', name: { value: 'Cat1', nlsKey: 'cat1' } }; + const category2 = { moduleName: 'testModule', name: { value: 'Cat2', nlsKey: 'cat2' } }; + const result = (0, render_js_1.renderADML)('VS Code', ['1.0'], [category1, category2], [mockPolicy]); + assert_1.default.ok(result.includes('Category_cat1')); + assert_1.default.ok(result.includes('Category_cat2')); + }); + }); + suite('renderProfileManifest', () => { + const mockCategory = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + const mockPolicy = { + name: 'TestPolicy', + type: types_js_1.PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: (translations) => ` +pfm_name +TestPolicy +pfm_description +${translations?.['testModule']?.['test.desc'] || 'Default Desc'} +` + }; + test('should render profile manifest with correct XML structure', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('')); + assert_1.default.ok(result.includes('')); + assert_1.default.ok(result.includes('')); + }); + test('should include app name', () => { + const result = (0, render_js_1.renderProfileManifest)('My App', 'com.example.myapp', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('My App Managed Settings')); + assert_1.default.ok(result.includes('My App')); + }); + test('should include bundle identifier', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('com.microsoft.vscode')); + }); + test('should include required payload fields', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('PayloadDescription')); + assert_1.default.ok(result.includes('PayloadDisplayName')); + assert_1.default.ok(result.includes('PayloadIdentifier')); + assert_1.default.ok(result.includes('PayloadType')); + assert_1.default.ok(result.includes('PayloadUUID')); + assert_1.default.ok(result.includes('PayloadVersion')); + assert_1.default.ok(result.includes('PayloadOrganization')); + }); + test('should include policy manifests in subkeys', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('pfm_subkeys')); + assert_1.default.ok(result.includes('TestPolicy')); + assert_1.default.ok(result.includes('Default Desc')); + }); + test('should pass translations to policy manifests', () => { + const translations = { + 'testModule': { + 'test.desc': 'Translated Description' + } + }; + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy], translations); + assert_1.default.ok(result.includes('Translated Description')); + }); + test('should include VS Code specific URLs', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('https://code.visualstudio.com/')); + assert_1.default.ok(result.includes('https://code.visualstudio.com/docs/setup/enterprise')); + }); + test('should include last modified date', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('pfm_last_modified')); + assert_1.default.ok(result.includes('')); + }); + test('should mark manifest as unique', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('pfm_unique')); + assert_1.default.ok(result.includes('')); + }); + test('should handle multiple policies', () => { + const policy2 = { + ...mockPolicy, + name: 'TestPolicy2', + renderProfileManifest: () => ` +pfm_name +TestPolicy2 +` + }; + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy, policy2]); + assert_1.default.ok(result.includes('TestPolicy')); + assert_1.default.ok(result.includes('TestPolicy2')); + }); + test('should set format version to 1', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('pfm_format_version')); + assert_1.default.ok(result.includes('1')); + }); + test('should set interaction to combined', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('pfm_interaction')); + assert_1.default.ok(result.includes('combined')); + }); + test('should set platform to macOS', () => { + const result = (0, render_js_1.renderProfileManifest)('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + assert_1.default.ok(result.includes('pfm_platforms')); + assert_1.default.ok(result.includes('macOS')); + }); + }); + suite('renderMacOSPolicy', () => { + const mockCategory = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + const mockPolicy = { + name: 'TestPolicy', + type: types_js_1.PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => ['TestPolicy', ''], + renderProfileManifest: (translations) => ` +pfm_name +TestPolicy +pfm_description +${translations?.['testModule']?.['test.desc'] || 'Default Desc'} +` + }; + test('should render complete macOS policy profile', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderMacOSPolicy)(product, [mockPolicy], []); + const expected = ` + + + + PayloadContent + + + PayloadDisplayName + VS Code + PayloadIdentifier + com.microsoft.vscode.uuid + PayloadType + com.microsoft.vscode + PayloadUUID + uuid + PayloadVersion + 1 + TestPolicy + + + + PayloadDescription + This profile manages VS Code. For more information see https://code.visualstudio.com/docs/setup/enterprise + PayloadDisplayName + VS Code + PayloadIdentifier + com.microsoft.vscode + PayloadOrganization + Microsoft + PayloadType + Configuration + PayloadUUID + payload-uuid + PayloadVersion + 1 + TargetDeviceType + 5 + +`; + assert_1.default.strictEqual(result.profile, expected); + }); + test('should include en-us manifest by default', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderMacOSPolicy)(product, [mockPolicy], []); + assert_1.default.strictEqual(result.manifests.length, 1); + assert_1.default.strictEqual(result.manifests[0].languageId, 'en-us'); + assert_1.default.ok(result.manifests[0].contents.includes('VS Code Managed Settings')); + }); + test('should include translations', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const translations = [ + { languageId: 'fr-fr', languageTranslations: { 'testModule': { 'test.desc': 'Description Française' } } }, + { languageId: 'de-de', languageTranslations: { 'testModule': { 'test.desc': 'Deutsche Beschreibung' } } } + ]; + const result = (0, render_js_1.renderMacOSPolicy)(product, [mockPolicy], translations); + assert_1.default.strictEqual(result.manifests.length, 3); // en-us + 2 translations + assert_1.default.strictEqual(result.manifests[0].languageId, 'en-us'); + assert_1.default.strictEqual(result.manifests[1].languageId, 'fr-fr'); + assert_1.default.strictEqual(result.manifests[2].languageId, 'de-de'); + assert_1.default.ok(result.manifests[1].contents.includes('Description Française')); + assert_1.default.ok(result.manifests[2].contents.includes('Deutsche Beschreibung')); + }); + test('should handle multiple policies with correct indentation', () => { + const policy2 = { + ...mockPolicy, + name: 'TestPolicy2', + renderProfile: () => ['TestPolicy2', 'test value'] + }; + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderMacOSPolicy)(product, [mockPolicy, policy2], []); + assert_1.default.ok(result.profile.includes('TestPolicy')); + assert_1.default.ok(result.profile.includes('')); + assert_1.default.ok(result.profile.includes('TestPolicy2')); + assert_1.default.ok(result.profile.includes('test value')); + }); + test('should use provided UUIDs in profile', () => { + const product = { + nameLong: 'My App', + darwinBundleIdentifier: 'com.example.app', + darwinProfilePayloadUUID: 'custom-payload-uuid', + darwinProfileUUID: 'custom-uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderMacOSPolicy)(product, [mockPolicy], []); + assert_1.default.ok(result.profile.includes('custom-payload-uuid')); + assert_1.default.ok(result.profile.includes('custom-uuid')); + assert_1.default.ok(result.profile.includes('com.example.app.custom-uuid')); + }); + test('should include enterprise documentation link', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderMacOSPolicy)(product, [mockPolicy], []); + assert_1.default.ok(result.profile.includes('https://code.visualstudio.com/docs/setup/enterprise')); + }); + test('should set TargetDeviceType to 5', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderMacOSPolicy)(product, [mockPolicy], []); + assert_1.default.ok(result.profile.includes('TargetDeviceType')); + assert_1.default.ok(result.profile.includes('5')); + }); + }); + suite('renderGP', () => { + const mockCategory = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + const mockPolicy = { + name: 'TestPolicy', + type: types_js_1.PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.85', + renderADMX: (regKey) => [ + ``, + ` `, + `` + ], + renderADMLStrings: (translations) => [ + `${translations?.['testModule']?.['test.policy'] || 'Test Policy'}` + ], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '' + }; + test('should render complete GP with ADMX and ADML', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.ok(result.admx); + assert_1.default.ok(result.adml); + assert_1.default.ok(Array.isArray(result.adml)); + }); + test('should include regKey in ADMX', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'CustomRegKey' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.ok(result.admx.includes('CustomRegKey')); + assert_1.default.ok(result.admx.includes('Software\\Policies\\Microsoft\\CustomRegKey')); + }); + test('should include en-us ADML by default', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.strictEqual(result.adml.length, 1); + assert_1.default.strictEqual(result.adml[0].languageId, 'en-us'); + assert_1.default.ok(result.adml[0].contents.includes('VS Code')); + }); + test('should include translations in ADML', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const translations = [ + { languageId: 'fr-fr', languageTranslations: { 'testModule': { 'test.policy': 'Politique de test' } } }, + { languageId: 'de-de', languageTranslations: { 'testModule': { 'test.policy': 'Testrichtlinie' } } } + ]; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], translations); + assert_1.default.strictEqual(result.adml.length, 3); // en-us + 2 translations + assert_1.default.strictEqual(result.adml[0].languageId, 'en-us'); + assert_1.default.strictEqual(result.adml[1].languageId, 'fr-fr'); + assert_1.default.strictEqual(result.adml[2].languageId, 'de-de'); + assert_1.default.ok(result.adml[1].contents.includes('Politique de test')); + assert_1.default.ok(result.adml[2].contents.includes('Testrichtlinie')); + }); + test('should pass versions to ADMX', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.ok(result.admx.includes('Supported_1_85')); + }); + test('should pass versions to ADML', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.ok(result.adml[0].contents.includes('VS Code >= 1.85')); + }); + test('should pass categories to ADMX', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.ok(result.admx.includes('test.category')); + }); + test('should pass categories to ADML', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.ok(result.adml[0].contents.includes('Category_test_category')); + }); + test('should handle multiple policies', () => { + const policy2 = { + ...mockPolicy, + name: 'TestPolicy2', + renderADMX: (regKey) => [ + ``, + ` `, + `` + ], + renderADMLStrings: () => ['Test Policy 2'] + }; + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy, policy2], []); + assert_1.default.ok(result.admx.includes('TestPolicy')); + assert_1.default.ok(result.admx.includes('TestPolicy2')); + assert_1.default.ok(result.adml[0].contents.includes('TestPolicy')); + assert_1.default.ok(result.adml[0].contents.includes('TestPolicy2')); + }); + test('should include app name in ADML', () => { + const product = { + nameLong: 'My Custom App', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.ok(result.adml[0].contents.includes('My Custom App')); + }); + test('should return structured result with admx and adml properties', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = (0, render_js_1.renderGP)(product, [mockPolicy], []); + assert_1.default.ok('admx' in result); + assert_1.default.ok('adml' in result); + assert_1.default.strictEqual(typeof result.admx, 'string'); + assert_1.default.ok(Array.isArray(result.adml)); + }); + }); +}); +//# sourceMappingURL=render.test.js.map \ No newline at end of file diff --git a/build/lib/test/render.test.ts b/build/lib/test/render.test.ts new file mode 100644 index 00000000000..cbe24ba0725 --- /dev/null +++ b/build/lib/test/render.test.ts @@ -0,0 +1,827 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { renderADMLString, renderProfileString, renderADMX, renderADML, renderProfileManifest, renderMacOSPolicy, renderGP } from '../policies/render.js'; +import { NlsString, LanguageTranslations, Category, Policy, PolicyType } from '../policies/types.js'; + +suite('Render Functions', () => { + + suite('renderADMLString', () => { + + test('should render ADML string without translations', () => { + const nlsString: NlsString = { + value: 'Test description', + nlsKey: 'test.description' + }; + + const result = renderADMLString('TestPrefix', 'testModule', nlsString); + + assert.strictEqual(result, 'Test description'); + }); + + test('should replace dots with underscores in nls key', () => { + const nlsString: NlsString = { + value: 'Test value', + nlsKey: 'my.test.nls.key' + }; + + const result = renderADMLString('Prefix', 'testModule', nlsString); + + assert.ok(result.includes('id="Prefix_my_test_nls_key"')); + }); + + test('should use translation when available', () => { + const nlsString: NlsString = { + value: 'Original value', + nlsKey: 'test.key' + }; + + const translations: LanguageTranslations = { + 'testModule': { + 'test.key': 'Translated value' + } + }; + + const result = renderADMLString('TestPrefix', 'testModule', nlsString, translations); + + assert.ok(result.includes('>Translated value')); + }); + + test('should fallback to original value when translation not found', () => { + const nlsString: NlsString = { + value: 'Original value', + nlsKey: 'test.key' + }; + + const translations: LanguageTranslations = { + 'testModule': { + 'other.key': 'Other translation' + } + }; + + const result = renderADMLString('TestPrefix', 'testModule', nlsString, translations); + + assert.ok(result.includes('>Original value')); + }); + }); + + suite('renderProfileString', () => { + + test('should render profile string without translations', () => { + const nlsString: NlsString = { + value: 'Profile description', + nlsKey: 'profile.description' + }; + + const result = renderProfileString('ProfilePrefix', 'testModule', nlsString); + + assert.strictEqual(result, 'Profile description'); + }); + + test('should use translation when available', () => { + const nlsString: NlsString = { + value: 'Original profile value', + nlsKey: 'profile.key' + }; + + const translations: LanguageTranslations = { + 'testModule': { + 'profile.key': 'Translated profile value' + } + }; + + const result = renderProfileString('ProfilePrefix', 'testModule', nlsString, translations); + + assert.strictEqual(result, 'Translated profile value'); + }); + + test('should fallback to original value when translation not found', () => { + const nlsString: NlsString = { + value: 'Original profile value', + nlsKey: 'profile.key' + }; + + const translations: LanguageTranslations = { + 'testModule': { + 'other.key': 'Other translation' + } + }; + + const result = renderProfileString('ProfilePrefix', 'testModule', nlsString, translations); + + assert.strictEqual(result, 'Original profile value'); + }); + }); + + suite('renderADMX', () => { + + const mockCategory: Category = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + + const mockPolicy: Policy = { + name: 'TestPolicy', + type: PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.85', + renderADMX: (regKey: string) => [ + ``, + ` `, + `` + ], + renderADMLStrings: () => ['Test Policy'], + renderADMLPresentation: () => '', + renderProfile: () => ['TestPolicy', ''], + renderProfileManifest: () => 'pfm_nameTestPolicy' + }; + + test('should render ADMX with correct XML structure', () => { + const result = renderADMX('VSCode', ['1.85'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('')); + assert.ok(result.includes('')); + }); + + test('should include policy namespaces with regKey', () => { + const result = renderADMX('TestApp', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes(' { + const result = renderADMX('VSCode', ['1.85.0', '1.90.1'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('Supported_1_85_0')); + assert.ok(result.includes('Supported_1_90_1')); + assert.ok(!result.includes('Supported_1.85.0')); + }); + + test('should include categories in correct structure', () => { + const result = renderADMX('VSCode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('')); + assert.ok(result.includes('')); + }); + + test('should include policies section', () => { + const result = renderADMX('VSCode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('')); + assert.ok(result.includes('TestPolicy')); + assert.ok(result.includes('')); + }); + + test('should handle multiple versions', () => { + const result = renderADMX('VSCode', ['1.0', '1.5', '2.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('Supported_1_0')); + assert.ok(result.includes('Supported_1_5')); + assert.ok(result.includes('Supported_2_0')); + }); + + test('should handle multiple categories', () => { + const category1: Category = { moduleName: 'testModule', name: { value: 'Cat1', nlsKey: 'cat1' } }; + const category2: Category = { moduleName: 'testModule', name: { value: 'Cat2', nlsKey: 'cat2' } }; + + const result = renderADMX('VSCode', ['1.0'], [category1, category2], [mockPolicy]); + + assert.ok(result.includes('Category_cat1')); + assert.ok(result.includes('Category_cat2')); + }); + + test('should handle multiple policies', () => { + const policy2: Policy = { + name: 'TestPolicy2', + type: PolicyType.String, + category: mockCategory, + minimumVersion: '1.85', + renderADMX: (regKey: string) => [ + ``, + ` `, + `` + ], + renderADMLStrings: () => ['Test Policy 2'], + renderADMLPresentation: () => '', + renderProfile: () => ['TestPolicy2', ''], + renderProfileManifest: () => 'pfm_nameTestPolicy2' + }; + const result = renderADMX('VSCode', ['1.0'], [mockCategory], [mockPolicy, policy2]); + + assert.ok(result.includes('TestPolicy')); + assert.ok(result.includes('TestPolicy2')); + }); + }); + + suite('renderADML', () => { + + const mockCategory: Category = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + + const mockPolicy: Policy = { + name: 'TestPolicy', + type: PolicyType.String, + category: mockCategory, + minimumVersion: '1.85', + renderADMX: () => [], + renderADMLStrings: (translations?: LanguageTranslations) => [ + `Test Policy ${translations?.['testModule']?.['test.policy'] || 'Default'}` + ], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '' + }; + + test('should render ADML with correct XML structure', () => { + const result = renderADML('VS Code', ['1.85'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('')); + assert.ok(result.includes('')); + }); + + test('should include application name', () => { + const result = renderADML('My Application', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('My Application')); + }); + + test('should include supported versions with escaped greater-than', () => { + const result = renderADML('VS Code', ['1.85', '1.90'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('VS Code >= 1.85')); + assert.ok(result.includes('VS Code >= 1.90')); + }); + + test('should include category strings', () => { + const result = renderADML('VS Code', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('Category_test_category')); + }); + + test('should include policy strings', () => { + const result = renderADML('VS Code', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('TestPolicy')); + assert.ok(result.includes('Test Policy Default')); + }); + + test('should include policy presentations', () => { + const result = renderADML('VS Code', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('')); + assert.ok(result.includes('')); + assert.ok(result.includes('')); + }); + + test('should pass translations to policy strings', () => { + const translations: LanguageTranslations = { + 'testModule': { + 'test.policy': 'Translated' + } + }; + + const result = renderADML('VS Code', ['1.0'], [mockCategory], [mockPolicy], translations); + + assert.ok(result.includes('Test Policy Translated')); + }); + + test('should handle multiple categories', () => { + const category1: Category = { moduleName: 'testModule', name: { value: 'Cat1', nlsKey: 'cat1' } }; + const category2: Category = { moduleName: 'testModule', name: { value: 'Cat2', nlsKey: 'cat2' } }; + + const result = renderADML('VS Code', ['1.0'], [category1, category2], [mockPolicy]); + + assert.ok(result.includes('Category_cat1')); + assert.ok(result.includes('Category_cat2')); + }); + }); + + suite('renderProfileManifest', () => { + + const mockCategory: Category = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + + const mockPolicy: Policy = { + name: 'TestPolicy', + type: PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: (translations?: LanguageTranslations) => ` +pfm_name +TestPolicy +pfm_description +${translations?.['testModule']?.['test.desc'] || 'Default Desc'} +` + }; + + test('should render profile manifest with correct XML structure', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('')); + assert.ok(result.includes('')); + assert.ok(result.includes('')); + }); + + test('should include app name', () => { + const result = renderProfileManifest('My App', 'com.example.myapp', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('My App Managed Settings')); + assert.ok(result.includes('My App')); + }); + + test('should include bundle identifier', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('com.microsoft.vscode')); + }); + + test('should include required payload fields', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('PayloadDescription')); + assert.ok(result.includes('PayloadDisplayName')); + assert.ok(result.includes('PayloadIdentifier')); + assert.ok(result.includes('PayloadType')); + assert.ok(result.includes('PayloadUUID')); + assert.ok(result.includes('PayloadVersion')); + assert.ok(result.includes('PayloadOrganization')); + }); + + test('should include policy manifests in subkeys', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('pfm_subkeys')); + assert.ok(result.includes('TestPolicy')); + assert.ok(result.includes('Default Desc')); + }); + + test('should pass translations to policy manifests', () => { + const translations: LanguageTranslations = { + 'testModule': { + 'test.desc': 'Translated Description' + } + }; + + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy], translations); + + assert.ok(result.includes('Translated Description')); + }); + + test('should include VS Code specific URLs', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('https://code.visualstudio.com/')); + assert.ok(result.includes('https://code.visualstudio.com/docs/setup/enterprise')); + }); + + test('should include last modified date', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('pfm_last_modified')); + assert.ok(result.includes('')); + }); + + test('should mark manifest as unique', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('pfm_unique')); + assert.ok(result.includes('')); + }); + + test('should handle multiple policies', () => { + const policy2: Policy = { + ...mockPolicy, + name: 'TestPolicy2', + renderProfileManifest: () => ` +pfm_name +TestPolicy2 +` + }; + + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy, policy2]); + + assert.ok(result.includes('TestPolicy')); + assert.ok(result.includes('TestPolicy2')); + }); + + test('should set format version to 1', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('pfm_format_version')); + assert.ok(result.includes('1')); + }); + + test('should set interaction to combined', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('pfm_interaction')); + assert.ok(result.includes('combined')); + }); + + test('should set platform to macOS', () => { + const result = renderProfileManifest('VS Code', 'com.microsoft.vscode', ['1.0'], [mockCategory], [mockPolicy]); + + assert.ok(result.includes('pfm_platforms')); + assert.ok(result.includes('macOS')); + }); + }); + + suite('renderMacOSPolicy', () => { + + const mockCategory: Category = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + + const mockPolicy: Policy = { + name: 'TestPolicy', + type: PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => ['TestPolicy', ''], + renderProfileManifest: (translations?: LanguageTranslations) => ` +pfm_name +TestPolicy +pfm_description +${translations?.['testModule']?.['test.desc'] || 'Default Desc'} +` + }; + + test('should render complete macOS policy profile', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderMacOSPolicy(product, [mockPolicy], []); + + const expected = ` + + + + PayloadContent + + + PayloadDisplayName + VS Code + PayloadIdentifier + com.microsoft.vscode.uuid + PayloadType + com.microsoft.vscode + PayloadUUID + uuid + PayloadVersion + 1 + TestPolicy + + + + PayloadDescription + This profile manages VS Code. For more information see https://code.visualstudio.com/docs/setup/enterprise + PayloadDisplayName + VS Code + PayloadIdentifier + com.microsoft.vscode + PayloadOrganization + Microsoft + PayloadType + Configuration + PayloadUUID + payload-uuid + PayloadVersion + 1 + TargetDeviceType + 5 + +`; + + assert.strictEqual(result.profile, expected); + }); + + test('should include en-us manifest by default', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderMacOSPolicy(product, [mockPolicy], []); + + assert.strictEqual(result.manifests.length, 1); + assert.strictEqual(result.manifests[0].languageId, 'en-us'); + assert.ok(result.manifests[0].contents.includes('VS Code Managed Settings')); + }); + + test('should include translations', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const translations = [ + { languageId: 'fr-fr', languageTranslations: { 'testModule': { 'test.desc': 'Description Française' } } }, + { languageId: 'de-de', languageTranslations: { 'testModule': { 'test.desc': 'Deutsche Beschreibung' } } } + ]; + + const result = renderMacOSPolicy(product, [mockPolicy], translations); + + assert.strictEqual(result.manifests.length, 3); // en-us + 2 translations + assert.strictEqual(result.manifests[0].languageId, 'en-us'); + assert.strictEqual(result.manifests[1].languageId, 'fr-fr'); + assert.strictEqual(result.manifests[2].languageId, 'de-de'); + + assert.ok(result.manifests[1].contents.includes('Description Française')); + assert.ok(result.manifests[2].contents.includes('Deutsche Beschreibung')); + }); + + test('should handle multiple policies with correct indentation', () => { + const policy2: Policy = { + ...mockPolicy, + name: 'TestPolicy2', + renderProfile: () => ['TestPolicy2', 'test value'] + }; + + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderMacOSPolicy(product, [mockPolicy, policy2], []); + + assert.ok(result.profile.includes('TestPolicy')); + assert.ok(result.profile.includes('')); + assert.ok(result.profile.includes('TestPolicy2')); + assert.ok(result.profile.includes('test value')); + }); + + test('should use provided UUIDs in profile', () => { + const product = { + nameLong: 'My App', + darwinBundleIdentifier: 'com.example.app', + darwinProfilePayloadUUID: 'custom-payload-uuid', + darwinProfileUUID: 'custom-uuid', + win32RegValueName: 'VSCode' + }; + const result = renderMacOSPolicy(product, [mockPolicy], []); + + assert.ok(result.profile.includes('custom-payload-uuid')); + assert.ok(result.profile.includes('custom-uuid')); + assert.ok(result.profile.includes('com.example.app.custom-uuid')); + }); + + test('should include enterprise documentation link', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderMacOSPolicy(product, [mockPolicy], []); + + assert.ok(result.profile.includes('https://code.visualstudio.com/docs/setup/enterprise')); + }); + + test('should set TargetDeviceType to 5', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderMacOSPolicy(product, [mockPolicy], []); + + assert.ok(result.profile.includes('TargetDeviceType')); + assert.ok(result.profile.includes('5')); + }); + }); + + suite('renderGP', () => { + + const mockCategory: Category = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + + const mockPolicy: Policy = { + name: 'TestPolicy', + type: PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.85', + renderADMX: (regKey: string) => [ + ``, + ` `, + `` + ], + renderADMLStrings: (translations?: LanguageTranslations) => [ + `${translations?.['testModule']?.['test.policy'] || 'Test Policy'}` + ], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '' + }; + + test('should render complete GP with ADMX and ADML', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.ok(result.admx); + assert.ok(result.adml); + assert.ok(Array.isArray(result.adml)); + }); + + test('should include regKey in ADMX', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'CustomRegKey' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.ok(result.admx.includes('CustomRegKey')); + assert.ok(result.admx.includes('Software\\Policies\\Microsoft\\CustomRegKey')); + }); + + test('should include en-us ADML by default', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.strictEqual(result.adml.length, 1); + assert.strictEqual(result.adml[0].languageId, 'en-us'); + assert.ok(result.adml[0].contents.includes('VS Code')); + }); + + test('should include translations in ADML', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const translations = [ + { languageId: 'fr-fr', languageTranslations: { 'testModule': { 'test.policy': 'Politique de test' } } }, + { languageId: 'de-de', languageTranslations: { 'testModule': { 'test.policy': 'Testrichtlinie' } } } + ]; + + const result = renderGP(product, [mockPolicy], translations); + + assert.strictEqual(result.adml.length, 3); // en-us + 2 translations + assert.strictEqual(result.adml[0].languageId, 'en-us'); + assert.strictEqual(result.adml[1].languageId, 'fr-fr'); + assert.strictEqual(result.adml[2].languageId, 'de-de'); + + assert.ok(result.adml[1].contents.includes('Politique de test')); + assert.ok(result.adml[2].contents.includes('Testrichtlinie')); + }); + + test('should pass versions to ADMX', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.ok(result.admx.includes('Supported_1_85')); + }); + + test('should pass versions to ADML', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.ok(result.adml[0].contents.includes('VS Code >= 1.85')); + }); + + test('should pass categories to ADMX', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.ok(result.admx.includes('test.category')); + }); + + test('should pass categories to ADML', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.ok(result.adml[0].contents.includes('Category_test_category')); + }); + + test('should handle multiple policies', () => { + const policy2: Policy = { + ...mockPolicy, + name: 'TestPolicy2', + renderADMX: (regKey: string) => [ + ``, + ` `, + `` + ], + renderADMLStrings: () => ['Test Policy 2'] + }; + + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy, policy2], []); + + assert.ok(result.admx.includes('TestPolicy')); + assert.ok(result.admx.includes('TestPolicy2')); + assert.ok(result.adml[0].contents.includes('TestPolicy')); + assert.ok(result.adml[0].contents.includes('TestPolicy2')); + }); + + test('should include app name in ADML', () => { + const product = { + nameLong: 'My Custom App', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.ok(result.adml[0].contents.includes('My Custom App')); + }); + + test('should return structured result with admx and adml properties', () => { + const product = { + nameLong: 'VS Code', + darwinBundleIdentifier: 'com.microsoft.vscode', + darwinProfilePayloadUUID: 'payload-uuid', + darwinProfileUUID: 'uuid', + win32RegValueName: 'VSCode' + }; + const result = renderGP(product, [mockPolicy], []); + + assert.ok('admx' in result); + assert.ok('adml' in result); + assert.strictEqual(typeof result.admx, 'string'); + assert.ok(Array.isArray(result.adml)); + }); + }); +}); diff --git a/build/lib/test/stringEnumPolicy.test.js b/build/lib/test/stringEnumPolicy.test.js new file mode 100644 index 00000000000..8b45b754c0c --- /dev/null +++ b/build/lib/test/stringEnumPolicy.test.js @@ -0,0 +1,136 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const assert_1 = __importDefault(require("assert")); +const stringEnumPolicy_js_1 = require("../policies/stringEnumPolicy.js"); +const types_js_1 = require("../policies/types.js"); +suite('StringEnumPolicy', () => { + const mockCategory = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + const mockPolicy = { + key: 'test.stringenum.policy', + name: 'TestStringEnumPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'string', + localization: { + description: { key: 'test.policy.description', value: 'Test policy description' }, + enumDescriptions: [ + { key: 'test.option.one', value: 'Option One' }, + { key: 'test.option.two', value: 'Option Two' }, + { key: 'test.option.three', value: 'Option Three' } + ] + }, + enum: ['auto', 'manual', 'disabled'] + }; + test('should create StringEnumPolicy from factory method', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + assert_1.default.strictEqual(policy.name, 'TestStringEnumPolicy'); + assert_1.default.strictEqual(policy.minimumVersion, '1.0'); + assert_1.default.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert_1.default.strictEqual(policy.category.name.value, mockCategory.name.value); + assert_1.default.strictEqual(policy.type, types_js_1.PolicyType.StringEnum); + }); + test('should render ADMX elements correctly', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admx = policy.renderADMX('TestKey'); + assert_1.default.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\tauto', + '\tmanual', + '\tdisabled', + '', + '\t', + '' + ]); + }); + test('should render ADML strings correctly', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admlStrings = policy.renderADMLStrings(); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestStringEnumPolicy', + 'Test policy description', + 'Option One', + 'Option Two', + 'Option Three' + ]); + }); + test('should render ADML strings with translations', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated description', + 'test.option.one': 'Translated Option One', + 'test.option.two': 'Translated Option Two' + } + }; + const admlStrings = policy.renderADMLStrings(translations); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestStringEnumPolicy', + 'Translated description', + 'Translated Option One', + 'Translated Option Two', + 'Option Three' + ]); + }); + test('should render ADML presentation correctly', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const presentation = policy.renderADMLPresentation(); + assert_1.default.strictEqual(presentation, ''); + }); + test('should render profile value correctly', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profileValue = policy.renderProfileValue(); + assert_1.default.strictEqual(profileValue, 'auto'); + }); + test('should render profile correctly', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profile = policy.renderProfile(); + assert_1.default.strictEqual(profile.length, 2); + assert_1.default.strictEqual(profile[0], 'TestStringEnumPolicy'); + assert_1.default.strictEqual(profile[1], 'auto'); + }); + test('should render profile manifest value correctly', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifestValue = policy.renderProfileManifestValue(); + assert_1.default.strictEqual(manifestValue, 'pfm_default\nauto\npfm_description\nTest policy description\npfm_name\nTestStringEnumPolicy\npfm_title\nTestStringEnumPolicy\npfm_type\nstring\npfm_range_list\n\n\tauto\n\tmanual\n\tdisabled\n'); + }); + test('should render profile manifest value with translations', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + const manifestValue = policy.renderProfileManifestValue(translations); + assert_1.default.strictEqual(manifestValue, 'pfm_default\nauto\npfm_description\nTranslated manifest description\npfm_name\nTestStringEnumPolicy\npfm_title\nTestStringEnumPolicy\npfm_type\nstring\npfm_range_list\n\n\tauto\n\tmanual\n\tdisabled\n'); + }); + test('should render profile manifest correctly', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifest = policy.renderProfileManifest(); + assert_1.default.strictEqual(manifest, '\npfm_default\nauto\npfm_description\nTest policy description\npfm_name\nTestStringEnumPolicy\npfm_title\nTestStringEnumPolicy\npfm_type\nstring\npfm_range_list\n\n\tauto\n\tmanual\n\tdisabled\n\n'); + }); +}); +//# sourceMappingURL=stringEnumPolicy.test.js.map \ No newline at end of file diff --git a/build/lib/test/stringEnumPolicy.test.ts b/build/lib/test/stringEnumPolicy.test.ts new file mode 100644 index 00000000000..feac73ed44f --- /dev/null +++ b/build/lib/test/stringEnumPolicy.test.ts @@ -0,0 +1,174 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { StringEnumPolicy } from '../policies/stringEnumPolicy.js'; +import { LanguageTranslations, PolicyType } from '../policies/types.js'; +import { CategoryDto, PolicyDto } from '../policies/policyDto.js'; + +suite('StringEnumPolicy', () => { + const mockCategory: CategoryDto = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + + const mockPolicy: PolicyDto = { + key: 'test.stringenum.policy', + name: 'TestStringEnumPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'string', + localization: { + description: { key: 'test.policy.description', value: 'Test policy description' }, + enumDescriptions: [ + { key: 'test.option.one', value: 'Option One' }, + { key: 'test.option.two', value: 'Option Two' }, + { key: 'test.option.three', value: 'Option Three' } + ] + }, + enum: ['auto', 'manual', 'disabled'] + }; + + test('should create StringEnumPolicy from factory method', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + assert.strictEqual(policy.name, 'TestStringEnumPolicy'); + assert.strictEqual(policy.minimumVersion, '1.0'); + assert.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert.strictEqual(policy.category.name.value, mockCategory.name.value); + assert.strictEqual(policy.type, PolicyType.StringEnum); + }); + + test('should render ADMX elements correctly', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admx = policy.renderADMX('TestKey'); + + assert.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\tauto', + '\tmanual', + '\tdisabled', + '', + '\t', + '' + ]); + }); + + test('should render ADML strings correctly', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admlStrings = policy.renderADMLStrings(); + + assert.deepStrictEqual(admlStrings, [ + 'TestStringEnumPolicy', + 'Test policy description', + 'Option One', + 'Option Two', + 'Option Three' + ]); + }); + + test('should render ADML strings with translations', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated description', + 'test.option.one': 'Translated Option One', + 'test.option.two': 'Translated Option Two' + } + }; + + const admlStrings = policy.renderADMLStrings(translations); + + assert.deepStrictEqual(admlStrings, [ + 'TestStringEnumPolicy', + 'Translated description', + 'Translated Option One', + 'Translated Option Two', + 'Option Three' + ]); + }); + + test('should render ADML presentation correctly', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const presentation = policy.renderADMLPresentation(); + + assert.strictEqual(presentation, ''); + }); + + test('should render profile value correctly', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profileValue = policy.renderProfileValue(); + + assert.strictEqual(profileValue, 'auto'); + }); + + test('should render profile correctly', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profile = policy.renderProfile(); + + assert.strictEqual(profile.length, 2); + assert.strictEqual(profile[0], 'TestStringEnumPolicy'); + assert.strictEqual(profile[1], 'auto'); + }); + + test('should render profile manifest value correctly', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifestValue = policy.renderProfileManifestValue(); + + assert.strictEqual(manifestValue, 'pfm_default\nauto\npfm_description\nTest policy description\npfm_name\nTestStringEnumPolicy\npfm_title\nTestStringEnumPolicy\npfm_type\nstring\npfm_range_list\n\n\tauto\n\tmanual\n\tdisabled\n'); + }); + + test('should render profile manifest value with translations', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + + const manifestValue = policy.renderProfileManifestValue(translations); + + assert.strictEqual(manifestValue, 'pfm_default\nauto\npfm_description\nTranslated manifest description\npfm_name\nTestStringEnumPolicy\npfm_title\nTestStringEnumPolicy\npfm_type\nstring\npfm_range_list\n\n\tauto\n\tmanual\n\tdisabled\n'); + }); + + test('should render profile manifest correctly', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifest = policy.renderProfileManifest(); + + assert.strictEqual(manifest, '\npfm_default\nauto\npfm_description\nTest policy description\npfm_name\nTestStringEnumPolicy\npfm_title\nTestStringEnumPolicy\npfm_type\nstring\npfm_range_list\n\n\tauto\n\tmanual\n\tdisabled\n\n'); + }); +}); diff --git a/build/lib/test/stringPolicy.test.js b/build/lib/test/stringPolicy.test.js new file mode 100644 index 00000000000..75d6365878c --- /dev/null +++ b/build/lib/test/stringPolicy.test.js @@ -0,0 +1,119 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const assert_1 = __importDefault(require("assert")); +const stringPolicy_js_1 = require("../policies/stringPolicy.js"); +const types_js_1 = require("../policies/types.js"); +suite('StringPolicy', () => { + const mockCategory = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + const mockPolicy = { + key: 'test.string.policy', + name: 'TestStringPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'string', + default: '', + localization: { + description: { key: 'test.policy.description', value: 'Test string policy description' } + } + }; + test('should create StringPolicy from factory method', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + assert_1.default.strictEqual(policy.name, 'TestStringPolicy'); + assert_1.default.strictEqual(policy.minimumVersion, '1.0'); + assert_1.default.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert_1.default.strictEqual(policy.category.name.value, mockCategory.name.value); + assert_1.default.strictEqual(policy.type, types_js_1.PolicyType.String); + }); + test('should render ADMX elements correctly', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admx = policy.renderADMX('TestKey'); + assert_1.default.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\t', + '' + ]); + }); + test('should render ADML strings correctly', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const admlStrings = policy.renderADMLStrings(); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestStringPolicy', + 'Test string policy description' + ]); + }); + test('should render ADML strings with translations', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated description' + } + }; + const admlStrings = policy.renderADMLStrings(translations); + assert_1.default.deepStrictEqual(admlStrings, [ + 'TestStringPolicy', + 'Translated description' + ]); + }); + test('should render ADML presentation correctly', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const presentation = policy.renderADMLPresentation(); + assert_1.default.strictEqual(presentation, ''); + }); + test('should render profile value correctly', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profileValue = policy.renderProfileValue(); + assert_1.default.strictEqual(profileValue, ''); + }); + test('should render profile correctly', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const profile = policy.renderProfile(); + assert_1.default.strictEqual(profile.length, 2); + assert_1.default.strictEqual(profile[0], 'TestStringPolicy'); + assert_1.default.strictEqual(profile[1], ''); + }); + test('should render profile manifest value correctly', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifestValue = policy.renderProfileManifestValue(); + assert_1.default.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTest string policy description\npfm_name\nTestStringPolicy\npfm_title\nTestStringPolicy\npfm_type\nstring'); + }); + test('should render profile manifest value with translations', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const translations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + const manifestValue = policy.renderProfileManifestValue(translations); + assert_1.default.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTranslated manifest description\npfm_name\nTestStringPolicy\npfm_title\nTestStringPolicy\npfm_type\nstring'); + }); + test('should render profile manifest correctly', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const manifest = policy.renderProfileManifest(); + assert_1.default.strictEqual(manifest, '\npfm_default\n\npfm_description\nTest string policy description\npfm_name\nTestStringPolicy\npfm_title\nTestStringPolicy\npfm_type\nstring\n'); + }); +}); +//# sourceMappingURL=stringPolicy.test.js.map \ No newline at end of file diff --git a/build/lib/test/stringPolicy.test.ts b/build/lib/test/stringPolicy.test.ts new file mode 100644 index 00000000000..ae692d82bbe --- /dev/null +++ b/build/lib/test/stringPolicy.test.ts @@ -0,0 +1,157 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { StringPolicy } from '../policies/stringPolicy.js'; +import { LanguageTranslations, PolicyType } from '../policies/types.js'; +import { CategoryDto, PolicyDto } from '../policies/policyDto.js'; + +suite('StringPolicy', () => { + const mockCategory: CategoryDto = { + key: 'test.category', + name: { value: 'Category1', key: 'test.category' }, + }; + + const mockPolicy: PolicyDto = { + key: 'test.string.policy', + name: 'TestStringPolicy', + category: 'Category1', + minimumVersion: '1.0', + type: 'string', + default: '', + localization: { + description: { key: 'test.policy.description', value: 'Test string policy description' } + } + }; + + test('should create StringPolicy from factory method', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + assert.strictEqual(policy.name, 'TestStringPolicy'); + assert.strictEqual(policy.minimumVersion, '1.0'); + assert.strictEqual(policy.category.name.nlsKey, mockCategory.name.key); + assert.strictEqual(policy.category.name.value, mockCategory.name.value); + assert.strictEqual(policy.type, PolicyType.String); + }); + + test('should render ADMX elements correctly', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admx = policy.renderADMX('TestKey'); + + assert.deepStrictEqual(admx, [ + '', + '\t', + '\t', + '\t', + '', + '\t', + '' + ]); + }); + + test('should render ADML strings correctly', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const admlStrings = policy.renderADMLStrings(); + + assert.deepStrictEqual(admlStrings, [ + 'TestStringPolicy', + 'Test string policy description' + ]); + }); + + test('should render ADML strings with translations', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated description' + } + }; + + const admlStrings = policy.renderADMLStrings(translations); + + assert.deepStrictEqual(admlStrings, [ + 'TestStringPolicy', + 'Translated description' + ]); + }); + + test('should render ADML presentation correctly', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const presentation = policy.renderADMLPresentation(); + + assert.strictEqual(presentation, ''); + }); + + test('should render profile value correctly', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profileValue = policy.renderProfileValue(); + + assert.strictEqual(profileValue, ''); + }); + + test('should render profile correctly', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const profile = policy.renderProfile(); + + assert.strictEqual(profile.length, 2); + assert.strictEqual(profile[0], 'TestStringPolicy'); + assert.strictEqual(profile[1], ''); + }); + + test('should render profile manifest value correctly', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifestValue = policy.renderProfileManifestValue(); + + assert.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTest string policy description\npfm_name\nTestStringPolicy\npfm_title\nTestStringPolicy\npfm_type\nstring'); + }); + + test('should render profile manifest value with translations', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const translations: LanguageTranslations = { + '': { + 'test.policy.description': 'Translated manifest description' + } + }; + + const manifestValue = policy.renderProfileManifestValue(translations); + + assert.strictEqual(manifestValue, 'pfm_default\n\npfm_description\nTranslated manifest description\npfm_name\nTestStringPolicy\npfm_title\nTestStringPolicy\npfm_type\nstring'); + }); + + test('should render profile manifest correctly', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const manifest = policy.renderProfileManifest(); + + assert.strictEqual(manifest, '\npfm_default\n\npfm_description\nTest string policy description\npfm_name\nTestStringPolicy\npfm_title\nTestStringPolicy\npfm_type\nstring\n'); + }); +}); diff --git a/build/package.json b/build/package.json index ef715fbfb6a..fedaea5e271 100644 --- a/build/package.json +++ b/build/package.json @@ -69,7 +69,8 @@ "build-ts": "cd .. && npx tsgo --project build/tsconfig.build.json", "compile": "npm run build-ts", "watch": "npm run build-ts -- --watch", - "npmCheckJs": "npm run build-ts -- --noEmit" + "npmCheckJs": "npm run build-ts -- --noEmit", + "test": "npx mocha --ui tdd 'lib/**/*.test.js'" }, "optionalDependencies": { "tree-sitter-typescript": "^0.23.2",