From e81696f60db0936e9622ba1074dbbb015e0652ca Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 22 Oct 2025 16:01:59 -0700 Subject: [PATCH] Add policy support for linux (#272579) --- build/lib/policies/basePolicy.ts | 1 + build/lib/policies/booleanPolicy.js | 3 + build/lib/policies/booleanPolicy.ts | 4 + build/lib/policies/numberPolicy.js | 3 + build/lib/policies/numberPolicy.ts | 4 + build/lib/policies/objectPolicy.js | 3 + build/lib/policies/objectPolicy.ts | 4 + build/lib/policies/policyGenerator.js | 15 +- build/lib/policies/policyGenerator.ts | 19 +- build/lib/policies/render.js | 8 + build/lib/policies/render.ts | 8 + build/lib/policies/stringEnumPolicy.js | 3 + build/lib/policies/stringEnumPolicy.ts | 4 + build/lib/policies/stringPolicy.js | 3 + build/lib/policies/stringPolicy.ts | 4 + build/lib/policies/types.ts | 1 + build/lib/test/booleanPolicy.test.js | 6 + build/lib/test/booleanPolicy.test.ts | 10 + .../test/fixtures/policies/linux/policy.json | 14 ++ build/lib/test/numberPolicy.test.js | 6 + build/lib/test/numberPolicy.test.ts | 10 + build/lib/test/objectPolicy.test.js | 6 + build/lib/test/objectPolicy.test.ts | 10 + build/lib/test/policyConversion.test.js | 10 + build/lib/test/policyConversion.test.ts | 15 +- build/lib/test/render.test.js | 184 ++++++++++++++- build/lib/test/render.test.ts | 216 +++++++++++++++++- build/lib/test/stringEnumPolicy.test.js | 6 + build/lib/test/stringEnumPolicy.test.ts | 10 + build/lib/test/stringPolicy.test.js | 6 + build/lib/test/stringPolicy.test.ts | 10 + src/vs/base/common/policy.ts | 5 + src/vs/code/electron-main/main.ts | 5 +- src/vs/code/node/cliProcessMain.ts | 5 +- 34 files changed, 600 insertions(+), 21 deletions(-) create mode 100644 build/lib/test/fixtures/policies/linux/policy.json diff --git a/build/lib/policies/basePolicy.ts b/build/lib/policies/basePolicy.ts index 064467f7485..f0477d244f0 100644 --- a/build/lib/policies/basePolicy.ts +++ b/build/lib/policies/basePolicy.ts @@ -57,6 +57,7 @@ ${this.renderProfileManifestValue(translations)} `; } + abstract renderJsonValue(): string | number | boolean | object | null; abstract renderProfileValue(): string; abstract renderProfileManifestValue(translations?: LanguageTranslations): string; } diff --git a/build/lib/policies/booleanPolicy.js b/build/lib/policies/booleanPolicy.js index 1ec18d003ec..b7772650337 100644 --- a/build/lib/policies/booleanPolicy.js +++ b/build/lib/policies/booleanPolicy.js @@ -29,6 +29,9 @@ class BooleanPolicy extends basePolicy_1.BasePolicy { renderADMLPresentationContents() { return `${this.name}`; } + renderJsonValue() { + return false; + } renderProfileValue() { return ``; } diff --git a/build/lib/policies/booleanPolicy.ts b/build/lib/policies/booleanPolicy.ts index b37bb1e1816..538140b3db2 100644 --- a/build/lib/policies/booleanPolicy.ts +++ b/build/lib/policies/booleanPolicy.ts @@ -42,6 +42,10 @@ export class BooleanPolicy extends BasePolicy { return `${this.name}`; } + renderJsonValue() { + return false; + } + renderProfileValue(): string { return ``; } diff --git a/build/lib/policies/numberPolicy.js b/build/lib/policies/numberPolicy.js index 4cdc03ef738..62f6981f01a 100644 --- a/build/lib/policies/numberPolicy.js +++ b/build/lib/policies/numberPolicy.js @@ -33,6 +33,9 @@ class NumberPolicy extends basePolicy_1.BasePolicy { renderADMLPresentationContents() { return `${this.name}`; } + renderJsonValue() { + return this.defaultValue; + } renderProfileValue() { return `${this.defaultValue}`; } diff --git a/build/lib/policies/numberPolicy.ts b/build/lib/policies/numberPolicy.ts index 9bbbbddc07e..db4143e1f7f 100644 --- a/build/lib/policies/numberPolicy.ts +++ b/build/lib/policies/numberPolicy.ts @@ -46,6 +46,10 @@ export class NumberPolicy extends BasePolicy { return `${this.name}`; } + renderJsonValue() { + return this.defaultValue; + } + renderProfileValue() { return `${this.defaultValue}`; } diff --git a/build/lib/policies/objectPolicy.js b/build/lib/policies/objectPolicy.js index ab15ce9ec3e..be83c76613d 100644 --- a/build/lib/policies/objectPolicy.js +++ b/build/lib/policies/objectPolicy.js @@ -25,6 +25,9 @@ class ObjectPolicy extends basePolicy_1.BasePolicy { renderADMLPresentationContents() { return ``; } + renderJsonValue() { + return ''; + } renderProfileValue() { return ``; } diff --git a/build/lib/policies/objectPolicy.ts b/build/lib/policies/objectPolicy.ts index 8e555133f38..3bbc916636f 100644 --- a/build/lib/policies/objectPolicy.ts +++ b/build/lib/policies/objectPolicy.ts @@ -38,6 +38,10 @@ export class ObjectPolicy extends BasePolicy { return ``; } + renderJsonValue() { + return ''; + } + renderProfileValue(): string { return ``; } diff --git a/build/lib/policies/policyGenerator.js b/build/lib/policies/policyGenerator.js index e9f97b49092..bd549b0092d 100644 --- a/build/lib/policies/policyGenerator.js +++ b/build/lib/policies/policyGenerator.js @@ -203,10 +203,18 @@ async function darwinMain(policies, translations) { await fs_1.promises.writeFile(path_1.default.join(languagePath, `${bundleIdentifier}.plist`), contents.replace(/\r?\n/g, '\n')); } } +async function linuxMain(policies) { + const root = '.build/policies/linux'; + const policyFileContents = JSON.stringify((0, render_1.renderJsonPolicies)(policies), undefined, 4); + await fs_1.promises.rm(root, { recursive: true, force: true }); + await fs_1.promises.mkdir(root, { recursive: true }); + const jsonPath = path_1.default.join(root, `policy.json`); + await fs_1.promises.writeFile(jsonPath, policyFileContents.replace(/\r?\n/g, '\n')); +} async function main() { const args = (0, minimist_1.default)(process.argv.slice(2)); if (args._.length !== 2) { - console.error(`Usage: node build/lib/policies `); + console.error(`Usage: node build/lib/policies `); process.exit(1); } const policyDataFile = args._[0]; @@ -218,8 +226,11 @@ async function main() { else if (platform === 'win32') { await windowsMain(policies, translations); } + else if (platform === 'linux') { + await linuxMain(policies); + } else { - console.error(`Usage: node build/lib/policies `); + console.error(`Usage: node build/lib/policies `); process.exit(1); } } diff --git a/build/lib/policies/policyGenerator.ts b/build/lib/policies/policyGenerator.ts index 4c5e1d616f7..50ea96b1280 100644 --- a/build/lib/policies/policyGenerator.ts +++ b/build/lib/policies/policyGenerator.ts @@ -14,7 +14,7 @@ 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'; +import { renderGP, renderJsonPolicies, renderMacOSPolicy } from './render'; const product = require('../../../product.json') as ProductJson; const packageJson = require('../../../package.json'); @@ -202,10 +202,21 @@ async function darwinMain(policies: Policy[], translations: Translations) { } } +async function linuxMain(policies: Policy[]) { + const root = '.build/policies/linux'; + const policyFileContents = JSON.stringify(renderJsonPolicies(policies), undefined, 4); + + await fs.rm(root, { recursive: true, force: true }); + await fs.mkdir(root, { recursive: true }); + + const jsonPath = path.join(root, `policy.json`); + await fs.writeFile(jsonPath, policyFileContents.replace(/\r?\n/g, '\n')); +} + async function main() { const args = minimist(process.argv.slice(2)); if (args._.length !== 2) { - console.error(`Usage: node build/lib/policies `); + console.error(`Usage: node build/lib/policies `); process.exit(1); } @@ -217,8 +228,10 @@ async function main() { await darwinMain(policies, translations); } else if (platform === 'win32') { await windowsMain(policies, translations); + } else if (platform === 'linux') { + await linuxMain(policies); } else { - console.error(`Usage: node build/lib/policies `); + console.error(`Usage: node build/lib/policies `); process.exit(1); } } diff --git a/build/lib/policies/render.js b/build/lib/policies/render.js index 7f312314e35..c867442cf50 100644 --- a/build/lib/policies/render.js +++ b/build/lib/policies/render.js @@ -7,6 +7,7 @@ exports.renderADML = renderADML; exports.renderProfileManifest = renderProfileManifest; exports.renderMacOSPolicy = renderMacOSPolicy; exports.renderGP = renderGP; +exports.renderJsonPolicies = renderJsonPolicies; function renderADMLString(prefix, moduleName, nlsString, translations) { let value; if (translations) { @@ -268,4 +269,11 @@ function renderGP(product, policies, translations) { ] }; } +function renderJsonPolicies(policies) { + const policyObject = {}; + for (const policy of policies) { + policyObject[policy.name] = policy.renderJsonValue(); + } + return policyObject; +} //# sourceMappingURL=render.js.map \ No newline at end of file diff --git a/build/lib/policies/render.ts b/build/lib/policies/render.ts index 8953a6b7fde..8aa4181753d 100644 --- a/build/lib/policies/render.ts +++ b/build/lib/policies/render.ts @@ -293,3 +293,11 @@ export function renderGP(product: ProductJson, policies: Policy[], translations: ] }; } + +export function renderJsonPolicies(policies: Policy[]) { + const policyObject: { [key: string]: string | number | boolean | object | null } = {}; + for (const policy of policies) { + policyObject[policy.name] = policy.renderJsonValue(); + } + return policyObject; +} diff --git a/build/lib/policies/stringEnumPolicy.js b/build/lib/policies/stringEnumPolicy.js index 03508238bab..2d43c275ea3 100644 --- a/build/lib/policies/stringEnumPolicy.js +++ b/build/lib/policies/stringEnumPolicy.js @@ -47,6 +47,9 @@ class StringEnumPolicy extends basePolicy_1.BasePolicy { renderADMLPresentationContents() { return ``; } + renderJsonValue() { + return this.enum_[0]; + } renderProfileValue() { return `${this.enum_[0]}`; } diff --git a/build/lib/policies/stringEnumPolicy.ts b/build/lib/policies/stringEnumPolicy.ts index b8f8263fb68..c4adabdace7 100644 --- a/build/lib/policies/stringEnumPolicy.ts +++ b/build/lib/policies/stringEnumPolicy.ts @@ -69,6 +69,10 @@ export class StringEnumPolicy extends BasePolicy { return ``; } + renderJsonValue() { + return this.enum_[0]; + } + renderProfileValue() { return `${this.enum_[0]}`; } diff --git a/build/lib/policies/stringPolicy.js b/build/lib/policies/stringPolicy.js index 493bc33af40..62018248e6a 100644 --- a/build/lib/policies/stringPolicy.js +++ b/build/lib/policies/stringPolicy.js @@ -22,6 +22,9 @@ class StringPolicy extends basePolicy_1.BasePolicy { renderADMXElements() { return [``]; } + renderJsonValue() { + return ''; + } renderADMLPresentationContents() { return ``; } diff --git a/build/lib/policies/stringPolicy.ts b/build/lib/policies/stringPolicy.ts index b18160640a8..e318a6165d8 100644 --- a/build/lib/policies/stringPolicy.ts +++ b/build/lib/policies/stringPolicy.ts @@ -34,6 +34,10 @@ export class StringPolicy extends BasePolicy { return [``]; } + renderJsonValue() { + return ''; + } + renderADMLPresentationContents() { return ``; } diff --git a/build/lib/policies/types.ts b/build/lib/policies/types.ts index 35e93c435ef..861b5205f69 100644 --- a/build/lib/policies/types.ts +++ b/build/lib/policies/types.ts @@ -23,6 +23,7 @@ export interface Policy { renderADMX(regKey: string): string[]; renderADMLStrings(translations?: LanguageTranslations): string[]; renderADMLPresentation(): string; + renderJsonValue(): string | number | boolean | object | null; renderProfile(): string[]; // https://github.com/ProfileManifests/ProfileManifests/wiki/Manifest-Format renderProfileManifest(translations?: LanguageTranslations): string; diff --git a/build/lib/test/booleanPolicy.test.js b/build/lib/test/booleanPolicy.test.js index 65bb0f5b88e..0c6ded63c2b 100644 --- a/build/lib/test/booleanPolicy.test.js +++ b/build/lib/test/booleanPolicy.test.js @@ -79,6 +79,12 @@ suite('BooleanPolicy', () => { const presentation = policy.renderADMLPresentation(); assert_1.default.strictEqual(presentation, 'TestBooleanPolicy'); }); + test('should render JSON value correctly', () => { + const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const jsonValue = policy.renderJsonValue(); + assert_1.default.strictEqual(jsonValue, false); + }); test('should render profile value correctly', () => { const policy = booleanPolicy_js_1.BooleanPolicy.from(mockCategory, mockPolicy); assert_1.default.ok(policy); diff --git a/build/lib/test/booleanPolicy.test.ts b/build/lib/test/booleanPolicy.test.ts index eed38d99d00..8da223530b9 100644 --- a/build/lib/test/booleanPolicy.test.ts +++ b/build/lib/test/booleanPolicy.test.ts @@ -98,6 +98,16 @@ suite('BooleanPolicy', () => { assert.strictEqual(presentation, 'TestBooleanPolicy'); }); + test('should render JSON value correctly', () => { + const policy = BooleanPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const jsonValue = policy.renderJsonValue(); + + assert.strictEqual(jsonValue, false); + }); + test('should render profile value correctly', () => { const policy = BooleanPolicy.from(mockCategory, mockPolicy); diff --git a/build/lib/test/fixtures/policies/linux/policy.json b/build/lib/test/fixtures/policies/linux/policy.json new file mode 100644 index 00000000000..3a941999da6 --- /dev/null +++ b/build/lib/test/fixtures/policies/linux/policy.json @@ -0,0 +1,14 @@ +{ + "ChatAgentExtensionTools": false, + "ChatAgentMode": false, + "ChatMCP": "none", + "ChatPromptFiles": false, + "ChatToolsAutoApprove": false, + "McpGalleryServiceUrl": "", + "AllowedExtensions": "", + "ExtensionGalleryServiceUrl": "", + "ChatToolsTerminalEnableAutoApprove": false, + "EnableFeedback": false, + "TelemetryLevel": "all", + "UpdateMode": "none" +} \ No newline at end of file diff --git a/build/lib/test/numberPolicy.test.js b/build/lib/test/numberPolicy.test.js index de3a73565be..9a1d498edde 100644 --- a/build/lib/test/numberPolicy.test.js +++ b/build/lib/test/numberPolicy.test.js @@ -78,6 +78,12 @@ suite('NumberPolicy', () => { const presentation = policy.renderADMLPresentation(); assert_1.default.strictEqual(presentation, 'TestNumberPolicy'); }); + test('should render JSON value correctly', () => { + const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const jsonValue = policy.renderJsonValue(); + assert_1.default.strictEqual(jsonValue, 42); + }); test('should render profile value correctly', () => { const policy = numberPolicy_js_1.NumberPolicy.from(mockCategory, mockPolicy); assert_1.default.ok(policy); diff --git a/build/lib/test/numberPolicy.test.ts b/build/lib/test/numberPolicy.test.ts index 4f27891ec61..dfb6276e34e 100644 --- a/build/lib/test/numberPolicy.test.ts +++ b/build/lib/test/numberPolicy.test.ts @@ -97,6 +97,16 @@ suite('NumberPolicy', () => { assert.strictEqual(presentation, 'TestNumberPolicy'); }); + test('should render JSON value correctly', () => { + const policy = NumberPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const jsonValue = policy.renderJsonValue(); + + assert.strictEqual(jsonValue, 42); + }); + test('should render profile value correctly', () => { const policy = NumberPolicy.from(mockCategory, mockPolicy); diff --git a/build/lib/test/objectPolicy.test.js b/build/lib/test/objectPolicy.test.js index 1c25d52cf61..987b45242c4 100644 --- a/build/lib/test/objectPolicy.test.js +++ b/build/lib/test/objectPolicy.test.js @@ -77,6 +77,12 @@ suite('ObjectPolicy', () => { const presentation = policy.renderADMLPresentation(); assert_1.default.strictEqual(presentation, ''); }); + test('should render JSON value correctly', () => { + const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const jsonValue = policy.renderJsonValue(); + assert_1.default.strictEqual(jsonValue, ''); + }); test('should render profile value correctly', () => { const policy = objectPolicy_js_1.ObjectPolicy.from(mockCategory, mockPolicy); assert_1.default.ok(policy); diff --git a/build/lib/test/objectPolicy.test.ts b/build/lib/test/objectPolicy.test.ts index a4c2638a52f..6012b8012da 100644 --- a/build/lib/test/objectPolicy.test.ts +++ b/build/lib/test/objectPolicy.test.ts @@ -96,6 +96,16 @@ suite('ObjectPolicy', () => { assert.strictEqual(presentation, ''); }); + test('should render JSON value correctly', () => { + const policy = ObjectPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const jsonValue = policy.renderJsonValue(); + + assert.strictEqual(jsonValue, ''); + }); + test('should render profile value correctly', () => { const policy = ObjectPolicy.from(mockCategory, mockPolicy); diff --git a/build/lib/test/policyConversion.test.js b/build/lib/test/policyConversion.test.js index 0f61c856f04..2e079b3106e 100644 --- a/build/lib/test/policyConversion.test.js +++ b/build/lib/test/policyConversion.test.js @@ -451,5 +451,15 @@ suite('Policy E2E conversion', () => { // Compare the rendered ADML with the fixture assert_1.default.strictEqual(frFrAdml.contents, expectedContent, 'Windows fr-fr ADML should match the fixture'); }); + test('should render Linux policy JSON from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = (0, render_1.renderJsonPolicies)(parsedPolicies); + // Load the expected fixture file + const fixturePath = path_1.default.join(__dirname, 'fixtures', 'policies', 'linux', 'policy.json'); + const expectedContent = await fs_1.promises.readFile(fixturePath, 'utf-8'); + const expectedJson = JSON.parse(expectedContent); + // Compare the rendered JSON with the fixture + assert_1.default.deepStrictEqual(result, expectedJson, 'Linux policy JSON 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 index 3be9fd8c10d..0610b0cd980 100644 --- a/build/lib/test/policyConversion.test.ts +++ b/build/lib/test/policyConversion.test.ts @@ -13,7 +13,7 @@ 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'; +import { renderGP, renderMacOSPolicy, renderJsonPolicies } from '../policies/render'; const PolicyTypes = [ BooleanPolicy, @@ -492,4 +492,17 @@ suite('Policy E2E conversion', () => { assert.strictEqual(frFrAdml.contents, expectedContent, 'Windows fr-fr ADML should match the fixture'); }); + test('should render Linux policy JSON from policies list', async () => { + const parsedPolicies = parsePolicies(policies); + const result = renderJsonPolicies(parsedPolicies); + + // Load the expected fixture file + const fixturePath = path.join(__dirname, 'fixtures', 'policies', 'linux', 'policy.json'); + const expectedContent = await fs.readFile(fixturePath, 'utf-8'); + const expectedJson = JSON.parse(expectedContent); + + // Compare the rendered JSON with the fixture + assert.deepStrictEqual(result, expectedJson, 'Linux policy JSON should match the fixture'); + }); + }); diff --git a/build/lib/test/render.test.js b/build/lib/test/render.test.js index 005460c6204..1853dda04e3 100644 --- a/build/lib/test/render.test.js +++ b/build/lib/test/render.test.js @@ -109,7 +109,8 @@ suite('Render Functions', () => { renderADMLStrings: () => ['Test Policy'], renderADMLPresentation: () => '', renderProfile: () => ['TestPolicy', ''], - renderProfileManifest: () => 'pfm_nameTestPolicy' + renderProfileManifest: () => 'pfm_nameTestPolicy', + renderJsonValue: () => null }; test('should render ADMX with correct XML structure', () => { const result = (0, render_js_1.renderADMX)('VSCode', ['1.85'], [mockCategory], [mockPolicy]); @@ -167,7 +168,8 @@ suite('Render Functions', () => { renderADMLStrings: () => ['Test Policy 2'], renderADMLPresentation: () => '', renderProfile: () => ['TestPolicy2', ''], - renderProfileManifest: () => 'pfm_nameTestPolicy2' + renderProfileManifest: () => 'pfm_nameTestPolicy2', + renderJsonValue: () => null }; const result = (0, render_js_1.renderADMX)('VSCode', ['1.0'], [mockCategory], [mockPolicy, policy2]); assert_1.default.ok(result.includes('TestPolicy')); @@ -190,7 +192,8 @@ suite('Render Functions', () => { ], renderADMLPresentation: () => '', renderProfile: () => [], - renderProfileManifest: () => '' + renderProfileManifest: () => '', + renderJsonValue: () => null }; test('should render ADML with correct XML structure', () => { const result = (0, render_js_1.renderADML)('VS Code', ['1.85'], [mockCategory], [mockPolicy]); @@ -258,7 +261,8 @@ suite('Render Functions', () => { TestPolicy pfm_description ${translations?.['testModule']?.['test.desc'] || 'Default Desc'} -` +`, + renderJsonValue: () => null }; 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]); @@ -364,7 +368,8 @@ suite('Render Functions', () => { TestPolicy pfm_description ${translations?.['testModule']?.['test.desc'] || 'Default Desc'} -` +`, + renderJsonValue: () => null }; test('should render complete macOS policy profile', () => { const product = { @@ -525,7 +530,8 @@ suite('Render Functions', () => { ], renderADMLPresentation: () => '', renderProfile: () => [], - renderProfileManifest: () => '' + renderProfileManifest: () => '', + renderJsonValue: () => null }; test('should render complete GP with ADMX and ADML', () => { const product = { @@ -679,5 +685,171 @@ suite('Render Functions', () => { assert_1.default.ok(Array.isArray(result.adml)); }); }); + suite('renderJsonPolicies', () => { + const mockCategory = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + test('should render boolean policy JSON value', () => { + const booleanPolicy = { + name: 'BooleanPolicy', + type: types_js_1.PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => false + }; + const result = (0, render_js_1.renderJsonPolicies)([booleanPolicy]); + assert_1.default.deepStrictEqual(result, { BooleanPolicy: false }); + }); + test('should render number policy JSON value', () => { + const numberPolicy = { + name: 'NumberPolicy', + type: types_js_1.PolicyType.Number, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => 42 + }; + const result = (0, render_js_1.renderJsonPolicies)([numberPolicy]); + assert_1.default.deepStrictEqual(result, { NumberPolicy: 42 }); + }); + test('should render string policy JSON value', () => { + const stringPolicy = { + name: 'StringPolicy', + type: types_js_1.PolicyType.String, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => '' + }; + const result = (0, render_js_1.renderJsonPolicies)([stringPolicy]); + assert_1.default.deepStrictEqual(result, { StringPolicy: '' }); + }); + test('should render string enum policy JSON value', () => { + const stringEnumPolicy = { + name: 'StringEnumPolicy', + type: types_js_1.PolicyType.StringEnum, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => 'auto' + }; + const result = (0, render_js_1.renderJsonPolicies)([stringEnumPolicy]); + assert_1.default.deepStrictEqual(result, { StringEnumPolicy: 'auto' }); + }); + test('should render object policy JSON value', () => { + const objectPolicy = { + name: 'ObjectPolicy', + type: types_js_1.PolicyType.Object, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => '' + }; + const result = (0, render_js_1.renderJsonPolicies)([objectPolicy]); + assert_1.default.deepStrictEqual(result, { ObjectPolicy: '' }); + }); + test('should render multiple policies', () => { + const booleanPolicy = { + name: 'BooleanPolicy', + type: types_js_1.PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => true + }; + const numberPolicy = { + name: 'NumberPolicy', + type: types_js_1.PolicyType.Number, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => 100 + }; + const stringPolicy = { + name: 'StringPolicy', + type: types_js_1.PolicyType.String, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => 'test-value' + }; + const result = (0, render_js_1.renderJsonPolicies)([booleanPolicy, numberPolicy, stringPolicy]); + assert_1.default.deepStrictEqual(result, { + BooleanPolicy: true, + NumberPolicy: 100, + StringPolicy: 'test-value' + }); + }); + test('should handle empty policies array', () => { + const result = (0, render_js_1.renderJsonPolicies)([]); + assert_1.default.deepStrictEqual(result, {}); + }); + test('should handle null JSON value', () => { + const nullPolicy = { + name: 'NullPolicy', + type: types_js_1.PolicyType.String, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => null + }; + const result = (0, render_js_1.renderJsonPolicies)([nullPolicy]); + assert_1.default.deepStrictEqual(result, { NullPolicy: null }); + }); + test('should handle object JSON value', () => { + const objectPolicy = { + name: 'ComplexObjectPolicy', + type: types_js_1.PolicyType.Object, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => ({ nested: { value: 123 } }) + }; + const result = (0, render_js_1.renderJsonPolicies)([objectPolicy]); + assert_1.default.deepStrictEqual(result, { ComplexObjectPolicy: { nested: { value: 123 } } }); + }); + }); }); //# 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 index cbe24ba0725..325831247c4 100644 --- a/build/lib/test/render.test.ts +++ b/build/lib/test/render.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import assert from 'assert'; -import { renderADMLString, renderProfileString, renderADMX, renderADML, renderProfileManifest, renderMacOSPolicy, renderGP } from '../policies/render.js'; +import { renderADMLString, renderProfileString, renderADMX, renderADML, renderProfileManifest, renderMacOSPolicy, renderGP, renderJsonPolicies } from '../policies/render.js'; import { NlsString, LanguageTranslations, Category, Policy, PolicyType } from '../policies/types.js'; suite('Render Functions', () => { @@ -136,7 +136,8 @@ suite('Render Functions', () => { renderADMLStrings: () => ['Test Policy'], renderADMLPresentation: () => '', renderProfile: () => ['TestPolicy', ''], - renderProfileManifest: () => 'pfm_nameTestPolicy' + renderProfileManifest: () => 'pfm_nameTestPolicy', + renderJsonValue: () => null }; test('should render ADMX with correct XML structure', () => { @@ -210,7 +211,8 @@ suite('Render Functions', () => { renderADMLStrings: () => ['Test Policy 2'], renderADMLPresentation: () => '', renderProfile: () => ['TestPolicy2', ''], - renderProfileManifest: () => 'pfm_nameTestPolicy2' + renderProfileManifest: () => 'pfm_nameTestPolicy2', + renderJsonValue: () => null }; const result = renderADMX('VSCode', ['1.0'], [mockCategory], [mockPolicy, policy2]); @@ -237,7 +239,8 @@ suite('Render Functions', () => { ], renderADMLPresentation: () => '', renderProfile: () => [], - renderProfileManifest: () => '' + renderProfileManifest: () => '', + renderJsonValue: () => null }; test('should render ADML with correct XML structure', () => { @@ -326,7 +329,8 @@ suite('Render Functions', () => { TestPolicy pfm_description ${translations?.['testModule']?.['test.desc'] || 'Default Desc'} -` +`, + renderJsonValue: () => null }; test('should render profile manifest with correct XML structure', () => { @@ -463,7 +467,8 @@ suite('Render Functions', () => { TestPolicy pfm_description ${translations?.['testModule']?.['test.desc'] || 'Default Desc'} -` +`, + renderJsonValue: () => null }; test('should render complete macOS policy profile', () => { @@ -645,7 +650,8 @@ suite('Render Functions', () => { ], renderADMLPresentation: () => '', renderProfile: () => [], - renderProfileManifest: () => '' + renderProfileManifest: () => '', + renderJsonValue: () => null }; test('should render complete GP with ADMX and ADML', () => { @@ -824,4 +830,200 @@ suite('Render Functions', () => { assert.ok(Array.isArray(result.adml)); }); }); + + suite('renderJsonPolicies', () => { + + const mockCategory: Category = { + moduleName: 'testModule', + name: { value: 'Test Category', nlsKey: 'test.category' } + }; + + test('should render boolean policy JSON value', () => { + const booleanPolicy: Policy = { + name: 'BooleanPolicy', + type: PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => false + }; + + const result = renderJsonPolicies([booleanPolicy]); + + assert.deepStrictEqual(result, { BooleanPolicy: false }); + }); + + test('should render number policy JSON value', () => { + const numberPolicy: Policy = { + name: 'NumberPolicy', + type: PolicyType.Number, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => 42 + }; + + const result = renderJsonPolicies([numberPolicy]); + + assert.deepStrictEqual(result, { NumberPolicy: 42 }); + }); + + test('should render string policy JSON value', () => { + const stringPolicy: Policy = { + name: 'StringPolicy', + type: PolicyType.String, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => '' + }; + + const result = renderJsonPolicies([stringPolicy]); + + assert.deepStrictEqual(result, { StringPolicy: '' }); + }); + + test('should render string enum policy JSON value', () => { + const stringEnumPolicy: Policy = { + name: 'StringEnumPolicy', + type: PolicyType.StringEnum, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => 'auto' + }; + + const result = renderJsonPolicies([stringEnumPolicy]); + + assert.deepStrictEqual(result, { StringEnumPolicy: 'auto' }); + }); + + test('should render object policy JSON value', () => { + const objectPolicy: Policy = { + name: 'ObjectPolicy', + type: PolicyType.Object, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => '' + }; + + const result = renderJsonPolicies([objectPolicy]); + + assert.deepStrictEqual(result, { ObjectPolicy: '' }); + }); + + test('should render multiple policies', () => { + const booleanPolicy: Policy = { + name: 'BooleanPolicy', + type: PolicyType.Boolean, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => true + }; + + const numberPolicy: Policy = { + name: 'NumberPolicy', + type: PolicyType.Number, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => 100 + }; + + const stringPolicy: Policy = { + name: 'StringPolicy', + type: PolicyType.String, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => 'test-value' + }; + + const result = renderJsonPolicies([booleanPolicy, numberPolicy, stringPolicy]); + + assert.deepStrictEqual(result, { + BooleanPolicy: true, + NumberPolicy: 100, + StringPolicy: 'test-value' + }); + }); + + test('should handle empty policies array', () => { + const result = renderJsonPolicies([]); + + assert.deepStrictEqual(result, {}); + }); + + test('should handle null JSON value', () => { + const nullPolicy: Policy = { + name: 'NullPolicy', + type: PolicyType.String, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => null + }; + + const result = renderJsonPolicies([nullPolicy]); + + assert.deepStrictEqual(result, { NullPolicy: null }); + }); + + test('should handle object JSON value', () => { + const objectPolicy: Policy = { + name: 'ComplexObjectPolicy', + type: PolicyType.Object, + category: mockCategory, + minimumVersion: '1.0', + renderADMX: () => [], + renderADMLStrings: () => [], + renderADMLPresentation: () => '', + renderProfile: () => [], + renderProfileManifest: () => '', + renderJsonValue: () => ({ nested: { value: 123 } }) + }; + + const result = renderJsonPolicies([objectPolicy]); + + assert.deepStrictEqual(result, { ComplexObjectPolicy: { nested: { value: 123 } } }); + }); + }); }); diff --git a/build/lib/test/stringEnumPolicy.test.js b/build/lib/test/stringEnumPolicy.test.js index 8b45b754c0c..860ad3e6c0f 100644 --- a/build/lib/test/stringEnumPolicy.test.js +++ b/build/lib/test/stringEnumPolicy.test.js @@ -95,6 +95,12 @@ suite('StringEnumPolicy', () => { const presentation = policy.renderADMLPresentation(); assert_1.default.strictEqual(presentation, ''); }); + test('should render JSON value correctly', () => { + const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const jsonValue = policy.renderJsonValue(); + assert_1.default.strictEqual(jsonValue, 'auto'); + }); test('should render profile value correctly', () => { const policy = stringEnumPolicy_js_1.StringEnumPolicy.from(mockCategory, mockPolicy); assert_1.default.ok(policy); diff --git a/build/lib/test/stringEnumPolicy.test.ts b/build/lib/test/stringEnumPolicy.test.ts index feac73ed44f..3ee3856afd7 100644 --- a/build/lib/test/stringEnumPolicy.test.ts +++ b/build/lib/test/stringEnumPolicy.test.ts @@ -114,6 +114,16 @@ suite('StringEnumPolicy', () => { assert.strictEqual(presentation, ''); }); + test('should render JSON value correctly', () => { + const policy = StringEnumPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const jsonValue = policy.renderJsonValue(); + + assert.strictEqual(jsonValue, 'auto'); + }); + test('should render profile value correctly', () => { const policy = StringEnumPolicy.from(mockCategory, mockPolicy); diff --git a/build/lib/test/stringPolicy.test.js b/build/lib/test/stringPolicy.test.js index 75d6365878c..059510ca89d 100644 --- a/build/lib/test/stringPolicy.test.js +++ b/build/lib/test/stringPolicy.test.js @@ -78,6 +78,12 @@ suite('StringPolicy', () => { const presentation = policy.renderADMLPresentation(); assert_1.default.strictEqual(presentation, ''); }); + test('should render JSON value correctly', () => { + const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); + assert_1.default.ok(policy); + const jsonValue = policy.renderJsonValue(); + assert_1.default.strictEqual(jsonValue, ''); + }); test('should render profile value correctly', () => { const policy = stringPolicy_js_1.StringPolicy.from(mockCategory, mockPolicy); assert_1.default.ok(policy); diff --git a/build/lib/test/stringPolicy.test.ts b/build/lib/test/stringPolicy.test.ts index ae692d82bbe..a76c38c7dcb 100644 --- a/build/lib/test/stringPolicy.test.ts +++ b/build/lib/test/stringPolicy.test.ts @@ -97,6 +97,16 @@ suite('StringPolicy', () => { assert.strictEqual(presentation, ''); }); + test('should render JSON value correctly', () => { + const policy = StringPolicy.from(mockCategory, mockPolicy); + + assert.ok(policy); + + const jsonValue = policy.renderJsonValue(); + + assert.strictEqual(jsonValue, ''); + }); + test('should render profile value correctly', () => { const policy = StringPolicy.from(mockCategory, mockPolicy); diff --git a/src/vs/base/common/policy.ts b/src/vs/base/common/policy.ts index 7fa484a477e..8141b0f9b5d 100644 --- a/src/vs/base/common/policy.ts +++ b/src/vs/base/common/policy.ts @@ -6,6 +6,11 @@ import { localize } from '../../nls.js'; import { IDefaultAccount } from './defaultAccount.js'; +/** + * System-wide policy file path for Linux systems. + */ +export const LINUX_SYSTEM_POLICY_FILE_PATH = '/etc/vscode/policy.json'; + export type PolicyName = string; export type LocalizedValue = { key: string; diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index fb06a689254..922e141d1ef 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -18,7 +18,7 @@ import { getPathLabel } from '../../base/common/labels.js'; import { Schemas } from '../../base/common/network.js'; import { basename, resolve } from '../../base/common/path.js'; import { mark } from '../../base/common/performance.js'; -import { IProcessEnvironment, isMacintosh, isWindows, OS } from '../../base/common/platform.js'; +import { IProcessEnvironment, isLinux, isMacintosh, isWindows, OS } from '../../base/common/platform.js'; import { cwd } from '../../base/common/process.js'; import { rtrim, trim } from '../../base/common/strings.js'; import { Promises as FSPromises } from '../../base/node/pfs.js'; @@ -73,6 +73,7 @@ import { SaveStrategy, StateService } from '../../platform/state/node/stateServi import { FileUserDataProvider } from '../../platform/userData/common/fileUserDataProvider.js'; import { addUNCHostToAllowlist, getUNCHost } from '../../base/node/unc.js'; import { ThemeMainService } from '../../platform/theme/electron-main/themeMainServiceImpl.js'; +import { LINUX_SYSTEM_POLICY_FILE_PATH } from '../../base/common/policy.js'; /** * The main VS Code entry point. @@ -204,6 +205,8 @@ class CodeMain { policyService = disposables.add(new NativePolicyService(logService, productService.win32RegValueName)); } else if (isMacintosh && productService.darwinBundleIdentifier) { policyService = disposables.add(new NativePolicyService(logService, productService.darwinBundleIdentifier)); + } else if (isLinux) { + policyService = disposables.add(new FilePolicyService(URI.file(LINUX_SYSTEM_POLICY_FILE_PATH), fileService, logService)); } else if (environmentMainService.policyFile) { policyService = disposables.add(new FilePolicyService(environmentMainService.policyFile, fileService, logService)); } else { diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index da60ab85a19..e0a2115ade8 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -12,7 +12,7 @@ import { isSigPipeError, onUnexpectedError, setUnexpectedErrorHandler } from '.. import { Disposable } from '../../base/common/lifecycle.js'; import { Schemas } from '../../base/common/network.js'; import { isAbsolute, join } from '../../base/common/path.js'; -import { isWindows, isMacintosh } from '../../base/common/platform.js'; +import { isWindows, isMacintosh, isLinux } from '../../base/common/platform.js'; import { cwd } from '../../base/common/process.js'; import { URI } from '../../base/common/uri.js'; import { IConfigurationService } from '../../platform/configuration/common/configuration.js'; @@ -76,6 +76,7 @@ import { McpGalleryService } from '../../platform/mcp/common/mcpGalleryService.j import { AllowedMcpServersService } from '../../platform/mcp/common/allowedMcpServersService.js'; import { IMcpGalleryManifestService } from '../../platform/mcp/common/mcpGalleryManifest.js'; import { McpGalleryManifestService } from '../../platform/mcp/common/mcpGalleryManifestService.js'; +import { LINUX_SYSTEM_POLICY_FILE_PATH } from '../../base/common/policy.js'; class CliMain extends Disposable { @@ -182,6 +183,8 @@ class CliMain extends Disposable { policyService = this._register(new NativePolicyService(logService, productService.win32RegValueName)); } else if (isMacintosh && productService.darwinBundleIdentifier) { policyService = this._register(new NativePolicyService(logService, productService.darwinBundleIdentifier)); + } else if (isLinux) { + policyService = this._register(new FilePolicyService(URI.file(LINUX_SYSTEM_POLICY_FILE_PATH), fileService, logService)); } else if (environmentService.policyFile) { policyService = this._register(new FilePolicyService(environmentService.policyFile, fileService, logService)); } else {