Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/extensionManagement/test/node/extensionDownloader.test.ts
5241 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { VSBuffer } from '../../../../base/common/buffer.js';
8
import { platform } from '../../../../base/common/platform.js';
9
import { arch } from '../../../../base/common/process.js';
10
import { joinPath } from '../../../../base/common/resources.js';
11
import { URI } from '../../../../base/common/uri.js';
12
import { generateUuid } from '../../../../base/common/uuid.js';
13
import { mock } from '../../../../base/test/common/mock.js';
14
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
15
import { INativeEnvironmentService } from '../../../environment/common/environment.js';
16
import { ExtensionSignatureVerificationCode, getTargetPlatform, IExtensionGalleryService, IGalleryExtension, IGalleryExtensionAssets, InstallOperation } from '../../common/extensionManagement.js';
17
import { getGalleryExtensionId } from '../../common/extensionManagementUtil.js';
18
import { ExtensionsDownloader } from '../../node/extensionDownloader.js';
19
import { IExtensionSignatureVerificationResult, IExtensionSignatureVerificationService } from '../../node/extensionSignatureVerificationService.js';
20
import { IFileService } from '../../../files/common/files.js';
21
import { FileService } from '../../../files/common/fileService.js';
22
import { InMemoryFileSystemProvider } from '../../../files/common/inMemoryFilesystemProvider.js';
23
import { TestInstantiationService } from '../../../instantiation/test/common/instantiationServiceMock.js';
24
import { ILogService, NullLogService } from '../../../log/common/log.js';
25
import { IUriIdentityService } from '../../../uriIdentity/common/uriIdentity.js';
26
import { UriIdentityService } from '../../../uriIdentity/common/uriIdentityService.js';
27
import { IStringDictionary } from '../../../../base/common/collections.js';
28
29
const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' });
30
31
class TestExtensionSignatureVerificationService extends mock<IExtensionSignatureVerificationService>() {
32
33
constructor(
34
private readonly verificationResult: string | boolean) {
35
super();
36
}
37
38
override async verify(): Promise<IExtensionSignatureVerificationResult | undefined> {
39
if (this.verificationResult === true) {
40
return {
41
code: ExtensionSignatureVerificationCode.Success
42
};
43
}
44
if (this.verificationResult === false) {
45
return undefined;
46
}
47
return {
48
code: this.verificationResult as ExtensionSignatureVerificationCode,
49
};
50
}
51
}
52
53
class TestExtensionDownloader extends ExtensionsDownloader {
54
protected override async validate(): Promise<void> { }
55
}
56
57
suite('ExtensionDownloader Tests', () => {
58
59
const disposables = ensureNoDisposablesAreLeakedInTestSuite();
60
let instantiationService: TestInstantiationService;
61
62
setup(() => {
63
instantiationService = disposables.add(new TestInstantiationService());
64
65
const logService = new NullLogService();
66
const fileService = disposables.add(new FileService(logService));
67
const fileSystemProvider = disposables.add(new InMemoryFileSystemProvider());
68
disposables.add(fileService.registerProvider(ROOT.scheme, fileSystemProvider));
69
70
instantiationService.stub(ILogService, logService);
71
instantiationService.stub(IFileService, fileService);
72
instantiationService.stub(ILogService, logService);
73
instantiationService.stub(IUriIdentityService, disposables.add(new UriIdentityService(fileService)));
74
instantiationService.stub(INativeEnvironmentService, { extensionsDownloadLocation: joinPath(ROOT, 'CachedExtensionVSIXs') });
75
instantiationService.stub(IExtensionGalleryService, {
76
async download(extension, location, operation) {
77
await fileService.writeFile(location, VSBuffer.fromString('extension vsix'));
78
},
79
async downloadSignatureArchive(extension, location) {
80
await fileService.writeFile(location, VSBuffer.fromString('extension signature'));
81
},
82
});
83
});
84
85
test('download completes successfully if verification is disabled by options', async () => {
86
const testObject = aTestObject({ verificationResult: 'error' });
87
88
const actual = await testObject.download(aGalleryExtension('a', { isSigned: true }), InstallOperation.Install, false);
89
90
assert.strictEqual(actual.verificationStatus, undefined);
91
});
92
93
test('download completes successfully if verification is disabled because the module is not loaded', async () => {
94
const testObject = aTestObject({ verificationResult: false });
95
96
const actual = await testObject.download(aGalleryExtension('a', { isSigned: true }), InstallOperation.Install, true);
97
98
assert.strictEqual(actual.verificationStatus, undefined);
99
});
100
101
test('download completes successfully if verification fails to execute', async () => {
102
const errorCode = 'ENOENT';
103
const testObject = aTestObject({ verificationResult: errorCode });
104
105
const actual = await testObject.download(aGalleryExtension('a', { isSigned: true }), InstallOperation.Install, true);
106
107
assert.strictEqual(actual.verificationStatus, errorCode);
108
});
109
110
test('download completes successfully if verification fails ', async () => {
111
const errorCode = 'IntegrityCheckFailed';
112
const testObject = aTestObject({ verificationResult: errorCode });
113
114
const actual = await testObject.download(aGalleryExtension('a', { isSigned: true }), InstallOperation.Install, true);
115
116
assert.strictEqual(actual.verificationStatus, errorCode);
117
});
118
119
test('download completes successfully if verification succeeds', async () => {
120
const testObject = aTestObject({ verificationResult: true });
121
122
const actual = await testObject.download(aGalleryExtension('a', { isSigned: true }), InstallOperation.Install, true);
123
124
assert.strictEqual(actual.verificationStatus, ExtensionSignatureVerificationCode.Success);
125
});
126
127
test('download completes successfully for unsigned extension', async () => {
128
const testObject = aTestObject({ verificationResult: true });
129
130
const actual = await testObject.download(aGalleryExtension('a', { isSigned: false }), InstallOperation.Install, true);
131
132
assert.strictEqual(actual.verificationStatus, ExtensionSignatureVerificationCode.NotSigned);
133
});
134
135
test('download completes successfully for an unsigned extension even when signature verification throws error', async () => {
136
const testObject = aTestObject({ verificationResult: 'error' });
137
138
const actual = await testObject.download(aGalleryExtension('a', { isSigned: false }), InstallOperation.Install, true);
139
140
assert.strictEqual(actual.verificationStatus, ExtensionSignatureVerificationCode.NotSigned);
141
});
142
143
function aTestObject(options: { verificationResult: boolean | string }): ExtensionsDownloader {
144
instantiationService.stub(IExtensionSignatureVerificationService, new TestExtensionSignatureVerificationService(options.verificationResult));
145
return disposables.add(instantiationService.createInstance(TestExtensionDownloader));
146
}
147
148
function aGalleryExtension(name: string, properties: Partial<IGalleryExtension> = {}, galleryExtensionProperties: IStringDictionary<unknown> = {}, assets: Partial<IGalleryExtensionAssets> = {}): IGalleryExtension {
149
const targetPlatform = getTargetPlatform(platform, arch);
150
const galleryExtension = <IGalleryExtension>Object.create({ name, publisher: 'pub', version: '1.0.0', allTargetPlatforms: [targetPlatform], properties: {}, assets: {}, ...properties });
151
galleryExtension.properties = { ...galleryExtension.properties, dependencies: [], targetPlatform, ...galleryExtensionProperties };
152
galleryExtension.assets = { ...galleryExtension.assets, ...assets };
153
galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() };
154
return <IGalleryExtension>galleryExtension;
155
}
156
});
157
158