From 27c05b0183812586652a346b32fe8b886c8daa2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Mon, 12 Aug 2024 15:49:58 +0200 Subject: [PATCH] allow custom NPM repo only when licensed --- packages/cli/src/License.ts | 4 +++ packages/cli/src/constants.ts | 1 + .../cli/src/controllers/e2e.controller.ts | 1 + .../communityPackages.service.test.ts | 4 +++ .../src/services/communityPackages.service.ts | 30 ++++++++++++------- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/License.ts b/packages/cli/src/License.ts index 643da18fd26e9..fc0d2cd45a235 100644 --- a/packages/cli/src/License.ts +++ b/packages/cli/src/License.ts @@ -305,6 +305,10 @@ export class License { return this.isFeatureEnabled(LICENSE_FEATURES.PROJECT_ROLE_VIEWER); } + isCustomNpmRegistryEnabled() { + return this.isFeatureEnabled(LICENSE_FEATURES.COMMUNITY_NODES_CUSTOM_REGISTRY); + } + getCurrentEntitlements() { return this.manager?.getCurrentEntitlements() ?? []; } diff --git a/packages/cli/src/constants.ts b/packages/cli/src/constants.ts index 41c95cb01ace6..dfb072576aa9f 100644 --- a/packages/cli/src/constants.ts +++ b/packages/cli/src/constants.ts @@ -90,6 +90,7 @@ export const LICENSE_FEATURES = { PROJECT_ROLE_ADMIN: 'feat:projectRole:admin', PROJECT_ROLE_EDITOR: 'feat:projectRole:editor', PROJECT_ROLE_VIEWER: 'feat:projectRole:viewer', + COMMUNITY_NODES_CUSTOM_REGISTRY: 'feat:communityNodes:customRegistry', } as const; export const LICENSE_QUOTAS = { diff --git a/packages/cli/src/controllers/e2e.controller.ts b/packages/cli/src/controllers/e2e.controller.ts index 3954bb1caf891..20224795052e8 100644 --- a/packages/cli/src/controllers/e2e.controller.ts +++ b/packages/cli/src/controllers/e2e.controller.ts @@ -87,6 +87,7 @@ export class E2EController { [LICENSE_FEATURES.PROJECT_ROLE_ADMIN]: false, [LICENSE_FEATURES.PROJECT_ROLE_EDITOR]: false, [LICENSE_FEATURES.PROJECT_ROLE_VIEWER]: false, + [LICENSE_FEATURES.COMMUNITY_NODES_CUSTOM_REGISTRY]: false, }; private numericFeatures: Record = { diff --git a/packages/cli/src/services/__tests__/communityPackages.service.test.ts b/packages/cli/src/services/__tests__/communityPackages.service.test.ts index 273a8c4bcb9e9..d6a5cb11d1ae5 100644 --- a/packages/cli/src/services/__tests__/communityPackages.service.test.ts +++ b/packages/cli/src/services/__tests__/communityPackages.service.test.ts @@ -20,6 +20,7 @@ import { InstalledNodesRepository } from '@db/repositories/installedNodes.reposi import { InstalledPackagesRepository } from '@db/repositories/installedPackages.repository'; import { InstalledNodes } from '@db/entities/InstalledNodes'; import type { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials'; +import type { License } from '@/License'; import { mockInstance } from '@test/mocking'; import { COMMUNITY_NODE_VERSION, COMMUNITY_PACKAGE_VERSION } from '@test-integration/constants'; @@ -39,6 +40,7 @@ const execMock = ((...args) => { }) as typeof exec; describe('CommunityPackagesService', () => { + const license = mock(); const globalConfig = mock({ nodes: { communityPackages: { @@ -75,6 +77,7 @@ describe('CommunityPackagesService', () => { mock(), loadNodesAndCredentials, mock(), + license, globalConfig, ); @@ -394,6 +397,7 @@ describe('CommunityPackagesService', () => { installedPackage.packageName = mockPackageName(); mocked(exec).mockImplementation(execMock); + license.isCustomNpmRegistryEnabled.mockReturnValue(true); // // ACT diff --git a/packages/cli/src/services/communityPackages.service.ts b/packages/cli/src/services/communityPackages.service.ts index 760069b299b9e..899fd6de30a0b 100644 --- a/packages/cli/src/services/communityPackages.service.ts +++ b/packages/cli/src/services/communityPackages.service.ts @@ -24,6 +24,9 @@ import type { CommunityPackages } from '@/Interfaces'; import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials'; import { Logger } from '@/Logger'; import { OrchestrationService } from './orchestration.service'; +import { License } from '@/License'; + +const DEFAULT_REGISTRY = 'https://registry.npmjs.org'; const { PACKAGE_NAME_NOT_PROVIDED, @@ -51,20 +54,15 @@ export class CommunityPackagesService { missingPackages: string[] = []; - private readonly registry: string; - constructor( private readonly instanceSettings: InstanceSettings, private readonly logger: Logger, private readonly installedPackageRepository: InstalledPackagesRepository, private readonly loadNodesAndCredentials: LoadNodesAndCredentials, private readonly orchestrationService: OrchestrationService, - globalConfig: GlobalConfig, - ) { - const { reinstallMissing, registry } = globalConfig.nodes.communityPackages; - this.reinstallMissingPackages = reinstallMissing; - this.registry = registry; - } + private readonly license: License, + private readonly globalConfig: GlobalConfig, + ) {} get hasMissingPackages() { return this.missingPackages.length > 0; @@ -283,7 +281,8 @@ export class CommunityPackagesService { if (missingPackages.size === 0) return; - if (this.reinstallMissingPackages) { + const { reinstallMissing } = this.globalConfig.nodes.communityPackages; + if (reinstallMissing) { this.logger.info('Attempting to reinstall missing packages', { missingPackages }); try { // Optimistic approach - stop if any installation fails @@ -325,13 +324,22 @@ export class CommunityPackagesService { await this.orchestrationService.publish('community-package-uninstall', { packageName }); } + private getNpmRegistry() { + let { registry } = this.globalConfig.nodes.communityPackages; + if (registry !== DEFAULT_REGISTRY && !this.license.isCustomNpmRegistryEnabled()) { + this.logger.warn('Not licensed to use custom NPM registry'); + registry = DEFAULT_REGISTRY; + } + return registry; + } + private async installOrUpdatePackage( packageName: string, options: { version?: string } | { installedPackage: InstalledPackages }, ) { const isUpdate = 'installedPackage' in options; const packageVersion = isUpdate || !options.version ? 'latest' : options.version; - const command = `npm install ${packageName}@${packageVersion} --registry=${this.registry}`; + const command = `npm install ${packageName}@${packageVersion} --registry=${this.getNpmRegistry()}`; try { await this.executeNpmCommand(command); @@ -384,7 +392,7 @@ export class CommunityPackagesService { async installOrUpdateNpmPackage(packageName: string, packageVersion: string) { await this.executeNpmCommand( - `npm install ${packageName}@${packageVersion} --registry=${this.registry}`, + `npm install ${packageName}@${packageVersion} --registry=${this.getNpmRegistry()}`, ); await this.loadNodesAndCredentials.loadPackage(packageName); await this.loadNodesAndCredentials.postProcessLoaders();