From d82b06c72b5e3e61286c28bf08ea7b544ecf9201 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Wed, 2 Apr 2025 14:57:34 -0300 Subject: [PATCH 1/5] Add LICENSE_KEY refresh job for self hosted instances --- .../ee/services/license/license-service.ts | 25 +++++++++++++++---- backend/src/server/routes/index.ts | 4 +++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index 29c36c7fe..7270dd121 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -5,6 +5,7 @@ // TODO(akhilmhdh): With tony find out the api structure and fill it here import { ForbiddenError } from "@casl/ability"; +import { CronJob } from "cron"; import { Knex } from "knex"; import { TKeyStoreFactory } from "@app/keystore/keystore"; @@ -85,6 +86,13 @@ export const licenseServiceFactory = ({ appCfg.LICENSE_KEY || "" ); + const syncLicenseKeyOnPremFeatures = async () => { + const { + data: { currentPlan } + } = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan"); + onPremFeatures = currentPlan; + }; + const init = async () => { try { if (appCfg.LICENSE_SERVER_KEY) { @@ -98,10 +106,7 @@ export const licenseServiceFactory = ({ if (appCfg.LICENSE_KEY) { const token = await licenseServerOnPremApi.refreshLicense(); if (token) { - const { - data: { currentPlan } - } = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan"); - onPremFeatures = currentPlan; + await syncLicenseKeyOnPremFeatures(); instanceType = InstanceType.EnterpriseOnPrem; logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`); isValidLicense = true; @@ -147,6 +152,15 @@ export const licenseServiceFactory = ({ } }; + const initializeBackgroundSync = async () => { + if (appCfg.LICENSE_KEY) { + logger.info("Setting up background sync process for refresh onPremFeatures"); + const job = new CronJob("*/10 * * * *", syncLicenseKeyOnPremFeatures); + job.start(); + return job; + } + }; + const getPlan = async (orgId: string, projectId?: string) => { logger.info(`getPlan: attempting to fetch plan for [orgId=${orgId}] [projectId=${projectId}]`); try { @@ -662,6 +676,7 @@ export const licenseServiceFactory = ({ getOrgTaxInvoices, getOrgTaxIds, addOrgTaxId, - delOrgTaxId + delOrgTaxId, + initializeBackgroundSync }; }; diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index dac88791f..eb463f092 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -1607,6 +1607,10 @@ export const registerRoutes = async ( if (rateLimitSyncJob) { cronJobs.push(rateLimitSyncJob); } + const licenseSyncJob = await licenseService.initializeBackgroundSync(); + if (licenseSyncJob) { + cronJobs.push(licenseSyncJob); + } } server.decorate("store", { From 7634fc94a61ca57bbc9780ba4a0941cc0eed7853 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Wed, 2 Apr 2025 16:34:42 -0300 Subject: [PATCH 2/5] Fix lint issue --- backend/src/lib/api-docs/constants.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index bd6056359..ca59c1fc8 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -633,7 +633,8 @@ export const FOLDERS = { path: "The path to list folders from.", directory: "The directory to list folders from. (Deprecated in favor of path)", recursive: "Whether or not to fetch all folders from the specified base path, and all of its subdirectories.", - lastSecretModified: "The timestamp used to filter folders with secrets modified after the specified date. The format for this timestamp is ISO 8601 (e.g. 2025-04-01T09:41:45-04:00)" + lastSecretModified: + "The timestamp used to filter folders with secrets modified after the specified date. The format for this timestamp is ISO 8601 (e.g. 2025-04-01T09:41:45-04:00)" }, GET_BY_ID: { folderId: "The ID of the folder to get details." From 064322936b30639fc14c0cd4085c37a58249e16c Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Wed, 2 Apr 2025 16:36:17 -0300 Subject: [PATCH 3/5] Add try-catch to syncLicenseKeyOnPremFeatures --- backend/src/ee/services/license/license-service.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index 7270dd121..ca6c2a699 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -87,10 +87,14 @@ export const licenseServiceFactory = ({ ); const syncLicenseKeyOnPremFeatures = async () => { - const { - data: { currentPlan } - } = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan"); - onPremFeatures = currentPlan; + try { + const { + data: { currentPlan } + } = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan"); + onPremFeatures = currentPlan; + } catch (error) { + logger.error(error, "Failed to synchronize license key features"); + } }; const init = async () => { From e87a1bd40240ecc341f8b26e41d7fa13eb367055 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Fri, 4 Apr 2025 10:55:30 -0300 Subject: [PATCH 4/5] Add flag to throw on syncLicenseKeyOnPremFeatures for the initial bootstrap --- backend/src/ee/services/license/license-service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index ca6c2a699..b996c8943 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -86,7 +86,7 @@ export const licenseServiceFactory = ({ appCfg.LICENSE_KEY || "" ); - const syncLicenseKeyOnPremFeatures = async () => { + const syncLicenseKeyOnPremFeatures = async (shouldThrow: boolean = false) => { try { const { data: { currentPlan } @@ -94,6 +94,7 @@ export const licenseServiceFactory = ({ onPremFeatures = currentPlan; } catch (error) { logger.error(error, "Failed to synchronize license key features"); + if (shouldThrow) throw error; } }; @@ -110,7 +111,7 @@ export const licenseServiceFactory = ({ if (appCfg.LICENSE_KEY) { const token = await licenseServerOnPremApi.refreshLicense(); if (token) { - await syncLicenseKeyOnPremFeatures(); + await syncLicenseKeyOnPremFeatures(true); instanceType = InstanceType.EnterpriseOnPrem; logger.info(`Instance type: ${InstanceType.EnterpriseOnPrem}`); isValidLicense = true; From 6c636415bbbcfd956ee56822aa0f8c8fe2ae5cd7 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Fri, 4 Apr 2025 12:53:28 -0300 Subject: [PATCH 5/5] Improve logs of syncLicenseKeyOnPremFeatures --- backend/src/ee/services/license/license-service.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index b996c8943..cf9818658 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -87,11 +87,13 @@ export const licenseServiceFactory = ({ ); const syncLicenseKeyOnPremFeatures = async (shouldThrow: boolean = false) => { + logger.info("Start syncing license key features"); try { const { data: { currentPlan } } = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan"); onPremFeatures = currentPlan; + logger.info("Successfully synchronized license key features"); } catch (error) { logger.error(error, "Failed to synchronize license key features"); if (shouldThrow) throw error;