fix: Fix issue with how entitlements are resolved for cloud (#319)

This commit is contained in:
Brendan Kellam 2025-05-28 17:35:18 -07:00 committed by GitHub
parent 0b52830b4f
commit 65cdaaa658
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 11 additions and 35 deletions

View file

@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
- Fixed issue with how entitlements are resolved for cloud. [#319](https://github.com/sourcebot-dev/sourcebot/pull/319)
## [4.0.0] - 2025-05-28
Sourcebot V4 introduces authentication, performance improvements and code navigation. Checkout the [migration guide](https://docs.sourcebot.dev/self-hosting/upgrade/v3-to-v4-guide) for information on upgrading your instance to v4.

View file

@ -3,9 +3,9 @@
const planLabels = {
oss: "OSS",
"cloud:team": "Team",
"cloud:demo": "Demo",
"self-hosted:enterprise": "Enterprise (Self-Hosted)",
"self-hosted:enterprise-unlimited": "Enterprise (Self-Hosted) Unlimited",
"self-hosted:enterprise-custom": "Enterprise (Self-Hosted) Custom",
} as const;
export type Plan = keyof typeof planLabels;
@ -21,14 +21,11 @@ const entitlements = [
] as const;
export type Entitlement = (typeof entitlements)[number];
export const isValidEntitlement = (entitlement: string): entitlement is Entitlement => {
return entitlements.includes(entitlement as Entitlement);
}
export const entitlementsByPlan: Record<Plan, Entitlement[]> = {
oss: [],
"cloud:team": ["billing", "multi-tenancy", "sso", "code-nav"],
"self-hosted:enterprise": ["search-contexts", "sso", "code-nav"],
"self-hosted:enterprise-unlimited": ["search-contexts", "public-access", "sso", "code-nav"],
"self-hosted:enterprise-custom": [],
// Special entitlement for https://demo.sourcebot.dev
"cloud:demo": ["public-access", "code-nav", "search-contexts"],
} as const;

View file

@ -1,5 +1,5 @@
import { env } from "@/env.mjs"
import { Entitlement, entitlementsByPlan, Plan, isValidEntitlement } from "./constants"
import { Entitlement, entitlementsByPlan, Plan } from "./constants"
import { base64Decode } from "@/lib/utils";
import { z } from "zod";
import { SOURCEBOT_SUPPORT_EMAIL } from "@/lib/constants";
@ -12,7 +12,6 @@ const eeLicenseKeyPayloadSchema = z.object({
seats: z.number(),
// ISO 8601 date string
expiryDate: z.string().datetime(),
customEntitlements: z.array(z.string()).optional()
});
type LicenseKeyPayload = z.infer<typeof eeLicenseKeyPayloadSchema>;
@ -39,6 +38,10 @@ export const getLicenseKey = (): LicenseKeyPayload | null => {
export const getPlan = (): Plan => {
if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT) {
if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === "demo") {
return "cloud:demo";
}
return "cloud:team";
}
@ -50,9 +53,6 @@ export const getPlan = (): Plan => {
process.exit(1);
}
if (licenseKey.customEntitlements) {
return "self-hosted:enterprise-custom";
}
return licenseKey.seats === SOURCEBOT_UNLIMITED_SEATS ? "self-hosted:enterprise-unlimited" : "self-hosted:enterprise";
} else {
console.info(`No valid license key found. Falling back to oss plan.`);
@ -71,30 +71,6 @@ export const hasEntitlement = (entitlement: Entitlement) => {
}
export const getEntitlements = (): Entitlement[] => {
const licenseKey = getLicenseKey();
if (!licenseKey) {
return entitlementsByPlan["oss"];
}
const plan = getPlan();
if (plan === "self-hosted:enterprise-custom") {
const customEntitlements = licenseKey.customEntitlements;
if (!customEntitlements) {
console.error(`The provided license key is under the self-hosted:enterprise-custom plan but has no custom entitlements. Returning oss entitlements.`);
return entitlementsByPlan["oss"];
}
const validCustomEntitlements: Entitlement[] = [];
for (const entitlement of customEntitlements) {
if (!isValidEntitlement(entitlement)) {
console.error(`Invalid custom entitlement "${entitlement}" provided in license key. Skipping.`);
continue;
}
validCustomEntitlements.push(entitlement as Entitlement);
}
return validCustomEntitlements;
}
return entitlementsByPlan[plan];
}