Skip to content

Commit 7421edc

Browse files
[CLC-2032] Fix Classic PAYG sunset bypass via websocket API (#21108)
The original sunset implementation only added checks to the new gRPC API (WorkspaceServiceAPI) but missed the legacy websocket API (GitpodServerImpl). This allowed users to bypass the sunset blocking through: - Gitpod CLI/Local App (uses experimental/v1 API) - JetBrains Gateway (uses websocket API directly) - Public API with Personal Access Tokens - Dashboard when feature flag is disabled This fix adds the sunset check to both startWorkspace() and createWorkspace() methods in GitpodServerImpl, using the same isWorkspaceStartBlockedBySunset() function that's already used in WorkspaceServiceAPI. The check: - Blocks installation-owned users (no organizationId) - Blocks users in non-exempted organizations - Exempts dedicated installations - Exempts organizations in the exemptedOrganizations list Co-authored-by: Ona <[email protected]>
1 parent d42b06d commit 7421edc

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

components/server/src/workspace/gitpod-server-impl.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ import { getPrimaryEmail } from "@gitpod/public-api-common/lib/user-utils";
139139
import { AnalyticsController } from "../analytics-controller";
140140
import { ClientHeaderFields } from "../express-util";
141141
import { filter } from "../util/objects";
142+
import { isWorkspaceStartBlockedBySunset } from "../util/featureflags";
142143

143144
// shortcut
144145
export const traceWI = (ctx: TraceContext, wi: Omit<LogContext, "userId">) => TraceContext.setOWI(ctx, wi); // userId is already taken care of in WebsocketConnectionManager
@@ -581,6 +582,16 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
581582
const { workspace, latestInstance: instance } = await this.workspaceService.getWorkspace(user.id, workspaceId);
582583
await this.guardAccess({ kind: "workspace", subject: workspace }, "get");
583584

585+
// Check if user is blocked by Classic PAYG sunset
586+
if (
587+
await isWorkspaceStartBlockedBySunset(user, workspace.organizationId, this.config.isDedicatedInstallation)
588+
) {
589+
throw new ApplicationError(
590+
ErrorCodes.PERMISSION_DENIED,
591+
"Gitpod Classic PAYG has sunset. Please visit https://app.ona.com/login to continue.",
592+
);
593+
}
594+
584595
// (gpl) We keep this check here for backwards compatibility, it should be superfluous in the future
585596
if (instance && instance.status.phase !== "stopped") {
586597
traceWI(ctx, { instanceId: instance.id });
@@ -850,6 +861,16 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
850861

851862
logContext = { userId: user.id };
852863

864+
// Check if user is blocked by Classic PAYG sunset
865+
if (
866+
await isWorkspaceStartBlockedBySunset(user, options.organizationId, this.config.isDedicatedInstallation)
867+
) {
868+
throw new ApplicationError(
869+
ErrorCodes.PERMISSION_DENIED,
870+
"Gitpod Classic PAYG has sunset. Please visit https://app.ona.com/login to continue.",
871+
);
872+
}
873+
853874
normalizedContextUrl = this.contextParser.normalizeContextURL(contextUrl);
854875

855876
const { context, project } = await this.contextService.parseContext(user, contextUrl, {

0 commit comments

Comments
 (0)