Skip to content

Commit 396f6b9

Browse files
add concept of License to the database and wire it into the enitlements system
1 parent 4f1b148 commit 396f6b9

File tree

67 files changed

+506
-319
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+506
-319
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { vi } from 'vitest';
2+
3+
export const prisma = {
4+
license: {
5+
findUnique: vi.fn().mockResolvedValue(null),
6+
},
7+
};

packages/backend/src/api.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { PrismaClient, RepoIndexingJobType } from '@sourcebot/db';
2-
import { createLogger, env, hasEntitlement, PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS } from '@sourcebot/shared';
2+
import { createLogger, env, PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS } from '@sourcebot/shared';
3+
import { hasEntitlement } from './entitlements.js';
34
import express, { Request, Response } from 'express';
45
import 'express-async-errors';
56
import * as http from "http";
@@ -100,7 +101,7 @@ export class Api {
100101
}
101102

102103
private async triggerAccountPermissionSync(req: Request, res: Response) {
103-
if (env.PERMISSION_SYNC_ENABLED !== 'true' || !hasEntitlement('permission-syncing')) {
104+
if (env.PERMISSION_SYNC_ENABLED !== 'true' || !await hasEntitlement('permission-syncing')) {
104105
res.status(403).json({ error: 'Permission syncing is not enabled.' });
105106
return;
106107
}

packages/backend/src/ee/accountPermissionSyncer.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as Sentry from "@sentry/node";
22
import { PrismaClient, AccountPermissionSyncJobStatus, Account, PermissionSyncSource} from "@sourcebot/db";
3-
import { env, hasEntitlement, createLogger, loadConfig, PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS } from "@sourcebot/shared";
3+
import { env, createLogger, loadConfig, PERMISSION_SYNC_SUPPORTED_IDENTITY_PROVIDERS } from "@sourcebot/shared";
4+
import { hasEntitlement } from "../entitlements.js";
45
import { ensureFreshAccountToken } from "./tokenRefresh.js";
56
import { Job, Queue, Worker } from "bullmq";
67
import { Redis } from "ioredis";
@@ -50,8 +51,8 @@ export class AccountPermissionSyncer {
5051
this.worker.on('failed', this.onJobFailed.bind(this));
5152
}
5253

53-
public startScheduler() {
54-
if (!hasEntitlement('permission-syncing')) {
54+
public async startScheduler() {
55+
if (!await hasEntitlement('permission-syncing')) {
5556
throw new Error('Permission syncing is not supported in current plan.');
5657
}
5758

packages/backend/src/ee/repoPermissionSyncer.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import * as Sentry from "@sentry/node";
22
import { PermissionSyncSource, PrismaClient, Repo, RepoPermissionSyncJobStatus } from "@sourcebot/db";
33
import { createLogger, PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES } from "@sourcebot/shared";
4-
import { env, hasEntitlement } from "@sourcebot/shared";
4+
import { env } from "@sourcebot/shared";
5+
import { hasEntitlement } from "../entitlements.js";
56
import { Job, Queue, Worker } from 'bullmq';
67
import { Redis } from 'ioredis';
78
import { createOctokitFromToken, getRepoCollaborators, GITHUB_CLOUD_HOSTNAME } from "../github.js";
@@ -44,8 +45,8 @@ export class RepoPermissionSyncer {
4445
this.worker.on('failed', this.onJobFailed.bind(this));
4546
}
4647

47-
public startScheduler() {
48-
if (!hasEntitlement('permission-syncing')) {
48+
public async startScheduler() {
49+
if (!await hasEntitlement('permission-syncing')) {
4950
throw new Error('Permission syncing is not supported in current plan.');
5051
}
5152

packages/backend/src/ee/syncSearchContexts.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ vi.mock('@sourcebot/shared', async (importOriginal) => {
1212
error: vi.fn(),
1313
debug: vi.fn(),
1414
})),
15-
hasEntitlement: vi.fn(() => true),
16-
getPlan: vi.fn(() => 'enterprise'),
1715
SOURCEBOT_SUPPORT_EMAIL: 'support@sourcebot.dev',
1816
};
1917
});
2018

19+
vi.mock('../entitlements.js', () => ({
20+
hasEntitlement: vi.fn(() => Promise.resolve(true)),
21+
getPlan: vi.fn(() => Promise.resolve('enterprise')),
22+
}));
23+
2124
import { syncSearchContexts } from './syncSearchContexts.js';
2225

2326
// Helper to build a repo record with GitLab topics stored in metadata.

packages/backend/src/ee/syncSearchContexts.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import micromatch from "micromatch";
22
import { createLogger } from "@sourcebot/shared";
33
import { PrismaClient } from "@sourcebot/db";
4-
import { getPlan, hasEntitlement, repoMetadataSchema, SOURCEBOT_SUPPORT_EMAIL } from "@sourcebot/shared";
4+
import { repoMetadataSchema, SOURCEBOT_SUPPORT_EMAIL } from "@sourcebot/shared";
5+
import { getPlan, hasEntitlement } from "../entitlements.js";
56
import { SearchContext } from "@sourcebot/schemas/v3/index.type";
67

78
const logger = createLogger('sync-search-contexts');
@@ -15,9 +16,9 @@ interface SyncSearchContextsParams {
1516
export const syncSearchContexts = async (params: SyncSearchContextsParams) => {
1617
const { contexts, orgId, db } = params;
1718

18-
if (!hasEntitlement("search-contexts")) {
19+
if (!await hasEntitlement("search-contexts")) {
1920
if (contexts) {
20-
const plan = getPlan();
21+
const plan = await getPlan();
2122
logger.warn(`Skipping search context sync. Reason: "Search contexts are not supported in your current plan: ${plan}. If you have a valid enterprise license key, pass it via SOURCEBOT_EE_LICENSE_KEY. For support, contact ${SOURCEBOT_SUPPORT_EMAIL}."`);
2223
}
2324
return false;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {
2+
Entitlement,
3+
Plan,
4+
getPlan as _getPlan,
5+
getSeats as _getSeats,
6+
hasEntitlement as _hasEntitlement,
7+
getEntitlements as _getEntitlements,
8+
} from "@sourcebot/shared";
9+
import { prisma } from "./prisma.js";
10+
import { SINGLE_TENANT_ORG_ID } from "./constants.js";
11+
12+
const getLicense = async () => {
13+
return prisma.license.findUnique({
14+
where: { orgId: SINGLE_TENANT_ORG_ID },
15+
});
16+
}
17+
18+
export const getPlan = async (): Promise<Plan> => {
19+
const license = await getLicense();
20+
return _getPlan(license);
21+
}
22+
23+
export const getSeats = async (): Promise<number> => {
24+
const license = await getLicense();
25+
return _getSeats(license);
26+
}
27+
28+
export const hasEntitlement = async (entitlement: Entitlement): Promise<boolean> => {
29+
const license = await getLicense();
30+
return _hasEntitlement(entitlement, license);
31+
}
32+
33+
export const getEntitlements = async (): Promise<Entitlement[]> => {
34+
const license = await getLicense();
35+
return _getEntitlements(license);
36+
}

packages/backend/src/github.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import * as Sentry from "@sentry/node";
44
import { getTokenFromConfig } from "@sourcebot/shared";
55
import { createLogger } from "@sourcebot/shared";
66
import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type";
7-
import { env, hasEntitlement } from "@sourcebot/shared";
7+
import { env } from "@sourcebot/shared";
8+
import { hasEntitlement } from "./entitlements.js";
89
import micromatch from "micromatch";
910
import pLimit from "p-limit";
1011
import { processPromiseResults, throwIfAnyFailed } from "./connectionUtils.js";
@@ -124,7 +125,7 @@ const getOctokitWithGithubApp = async (
124125
url: string | undefined,
125126
context: string
126127
): Promise<Octokit> => {
127-
if (!hasEntitlement('github-app') || !GithubAppManager.getInstance().appsConfigured()) {
128+
if (!await hasEntitlement('github-app') || !GithubAppManager.getInstance().appsConfigured()) {
128129
return octokit;
129130
}
130131

packages/backend/src/index.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import "./instrument.js";
22

33
import * as Sentry from "@sentry/node";
4-
import { PrismaClient } from "@sourcebot/db";
5-
import { createLogger, env, getConfigSettings, getDBConnectionString, hasEntitlement } from "@sourcebot/shared";
4+
import { createLogger, env, getConfigSettings } from "@sourcebot/shared";
5+
import { hasEntitlement } from "./entitlements.js";
6+
import { prisma } from "./prisma.js";
67
import 'express-async-errors';
78
import { existsSync } from 'fs';
89
import { mkdir } from 'fs/promises';
@@ -31,13 +32,6 @@ if (!existsSync(indexPath)) {
3132
await mkdir(indexPath, { recursive: true });
3233
}
3334

34-
const prisma = new PrismaClient({
35-
datasources: {
36-
db: {
37-
url: getDBConnectionString(),
38-
},
39-
},
40-
});
4135

4236
try {
4337
await redis.ping();
@@ -51,7 +45,7 @@ const promClient = new PromClient();
5145

5246
const settings = await getConfigSettings(env.CONFIG_PATH);
5347

54-
if (hasEntitlement('github-app')) {
48+
if (await hasEntitlement('github-app')) {
5549
await GithubAppManager.getInstance().init(prisma);
5650
}
5751

@@ -66,11 +60,11 @@ connectionManager.startScheduler();
6660
await repoIndexManager.startScheduler();
6761
auditLogPruner.startScheduler();
6862

69-
if (env.PERMISSION_SYNC_ENABLED === 'true' && !hasEntitlement('permission-syncing')) {
63+
if (env.PERMISSION_SYNC_ENABLED === 'true' && !await hasEntitlement('permission-syncing')) {
7064
logger.error('Permission syncing is not supported in current plan. Please contact team@sourcebot.dev for assistance.');
7165
process.exit(1);
7266
}
73-
else if (env.PERMISSION_SYNC_ENABLED === 'true' && hasEntitlement('permission-syncing')) {
67+
else if (env.PERMISSION_SYNC_ENABLED === 'true' && await hasEntitlement('permission-syncing')) {
7468
if (env.PERMISSION_SYNC_REPO_DRIVEN_ENABLED === 'true') {
7569
repoPermissionSyncer.startScheduler();
7670
}

packages/backend/src/prisma.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { PrismaClient } from "@sourcebot/db";
2+
import { getDBConnectionString } from "@sourcebot/shared";
3+
4+
export const prisma = new PrismaClient({
5+
datasources: {
6+
db: {
7+
url: getDBConnectionString(),
8+
},
9+
},
10+
});

0 commit comments

Comments
 (0)