Skip to content

Commit 2cbdd47

Browse files
committed
[server] Add organization image auth context to workspace image validation
Tool: gitpod/catfood.gitpod.cloud
1 parent 12f386b commit 2cbdd47

File tree

5 files changed

+35
-9
lines changed

5 files changed

+35
-9
lines changed

components/server/src/container-module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,9 @@ export const productionContainerModule = new ContainerModule(
412412
bind<DefaultWorkspaceImageValidator>(DefaultWorkspaceImageValidator)
413413
.toDynamicValue((ctx) =>
414414
// lazy load to avoid circular dependency
415-
async (userId: string, imageRef: string) => {
415+
async (userId: string, imageRef: string, organizationId?: string) => {
416416
const user = await ctx.container.get(UserService).findUserById(userId, userId);
417-
await ctx.container.get(WorkspaceService).validateImageRef({}, user, imageRef);
417+
await ctx.container.get(WorkspaceService).validateImageRef({}, user, imageRef, organizationId);
418418
},
419419
)
420420
.inSingletonScope();

components/server/src/orgs/default-workspace-image-validator.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
export type DefaultWorkspaceImageValidator = (userId: string, imageRef: string) => Promise<void>;
7+
export type DefaultWorkspaceImageValidator = (
8+
userId: string,
9+
imageRef: string,
10+
organizationId?: string,
11+
) => Promise<void>;
812
export const DefaultWorkspaceImageValidator = Symbol("DefaultWorkspaceImageValidator");

components/server/src/orgs/organization-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ export class OrganizationService {
493493
if (typeof settings.defaultWorkspaceImage === "string") {
494494
const defaultWorkspaceImage = settings.defaultWorkspaceImage.trim();
495495
if (defaultWorkspaceImage) {
496-
await this.validateDefaultWorkspaceImage(userId, defaultWorkspaceImage);
496+
await this.validateDefaultWorkspaceImage(userId, defaultWorkspaceImage, orgId);
497497
settings = { ...settings, defaultWorkspaceImage };
498498
} else {
499499
settings = { ...settings, defaultWorkspaceImage: null };

components/server/src/workspace/workspace-service.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,9 +1407,17 @@ export class WorkspaceService {
14071407
});
14081408
}
14091409

1410-
public async validateImageRef(ctx: TraceContext, user: User, imageRef: string) {
1410+
public async validateImageRef(ctx: TraceContext, user: User, imageRef: string, organizationId?: string) {
14111411
try {
1412-
return await this.workspaceStarter.resolveBaseImage(ctx, user, imageRef);
1412+
return await this.workspaceStarter.resolveBaseImage(
1413+
ctx,
1414+
user,
1415+
imageRef,
1416+
undefined,
1417+
undefined,
1418+
undefined,
1419+
organizationId,
1420+
);
14131421
} catch (e) {
14141422
// see https://github.com/gitpod-io/gitpod/blob/f3e41f8d86234e4101edff2199c54f50f8cbb656/components/image-builder-mk3/pkg/orchestrator/orchestrator.go#L561
14151423
// TODO(ak) ideally we won't check a message (subject to change)
@@ -1423,8 +1431,8 @@ export class WorkspaceService {
14231431
) {
14241432
let message = details;
14251433
// strip confusing prefix
1426-
if (details.startsWith("cannt resolve base image ref: ")) {
1427-
message = details.substring("cannt resolve base image ref: ".length);
1434+
if (details.startsWith("can't resolve base image ref: ")) {
1435+
message = details.substring("can't resolve base image ref: ".length);
14281436
}
14291437
throw new ApplicationError(ErrorCodes.BAD_REQUEST, message);
14301438
}

components/server/src/workspace/workspace-starter.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
ImageBuildLogInfo,
4343
ImageConfigFile,
4444
NamedWorkspaceFeatureFlag,
45+
OrgEnvVarWithValue,
4546
Permission,
4647
Project,
4748
RefType,
@@ -128,7 +129,7 @@ import { TokenProvider } from "../user/token-provider";
128129
import { UserAuthentication } from "../user/user-authentication";
129130
import { ImageSourceProvider } from "./image-source-provider";
130131
import { WorkspaceClassesConfig } from "./workspace-classes";
131-
import { SYSTEM_USER, SYSTEM_USER_ID } from "../authorization/authorizer";
132+
import { SYSTEM_USER, SYSTEM_USER_ID, Authorizer } from "../authorization/authorizer";
132133
import { EnvVarService, ResolvedEnvVars } from "../user/env-var-service";
133134
import { RedlockAbortSignal } from "redlock";
134135
import { ConfigProvider } from "./config-provider";
@@ -239,6 +240,7 @@ export class WorkspaceStarter {
239240
@inject(EnvVarService) private readonly envVarService: EnvVarService,
240241
@inject(OrganizationService) private readonly orgService: OrganizationService,
241242
@inject(ProjectsService) private readonly projectService: ProjectsService,
243+
@inject(Authorizer) private readonly auth: Authorizer,
242244
) {}
243245

244246
public async startWorkspace(
@@ -2033,6 +2035,7 @@ export class WorkspaceStarter {
20332035
workspace?: Workspace,
20342036
instance?: WorkspaceInstance,
20352037
region?: WorkspaceRegion,
2038+
organizationId?: string,
20362039
) {
20372040
const req = new ResolveBaseImageRequest();
20382041
req.setRef(imageRef);
@@ -2041,6 +2044,17 @@ export class WorkspaceStarter {
20412044
const auth = new BuildRegistryAuth();
20422045
auth.setTotal(allowAll);
20432046
req.setAuth(auth);
2047+
2048+
// if the image resolution is for an organization, we also include the organization's set up env vars
2049+
if (organizationId) {
2050+
await this.auth.checkPermissionOnOrganization(user.id, "read_env_var", organizationId);
2051+
const orgEnvVars = await this.orgDB.getOrgEnvironmentVariables(organizationId);
2052+
const orgEnvVarValues: OrgEnvVarWithValue[] = await this.orgDB.getOrgEnvironmentVariableValues(orgEnvVars);
2053+
2054+
const additionalAuth = await this.getAdditionalImageAuth({ workspace: orgEnvVarValues });
2055+
additionalAuth.forEach((val, key) => auth.getAdditionalMap().set(key, val));
2056+
}
2057+
20442058
const client = await this.getImageBuilderClient(user, workspace, instance, region);
20452059
return client.resolveBaseImage({ span: ctx.span }, req);
20462060
}

0 commit comments

Comments
 (0)