Skip to content

Commit 77f3fde

Browse files
[server] Add organization image auth context to workspace image validation (#20560)
* [server] Add organization image auth context to workspace image validation Tool: gitpod/catfood.gitpod.cloud * Introduce `listOrgEnvVarsWithValues` Tool: gitpod/catfood.gitpod.cloud
1 parent 12f386b commit 77f3fde

File tree

6 files changed

+37
-8
lines changed

6 files changed

+37
-8
lines changed

components/server/src/container-module.ts

+2-2
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

+5-1
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

+1-1
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/user/env-var-service.ts

+7
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ export class EnvVarService {
234234
return this.orgDB.getOrgEnvironmentVariables(orgId);
235235
}
236236

237+
async listOrgEnvVarsWithValues(requestorId: string, orgId: string): Promise<OrgEnvVarWithValue[]> {
238+
const envVars = (await ApplicationError.notFoundToUndefined(this.listOrgEnvVars(requestorId, orgId))) ?? [];
239+
const envVarValues = await this.orgDB.getOrgEnvironmentVariableValues(envVars);
240+
241+
return envVarValues;
242+
}
243+
237244
async getOrgEnvVarById(requestorId: string, id: string): Promise<OrgEnvVar> {
238245
const result = await this.orgDB.getOrgEnvironmentVariableById(id);
239246
if (!result) {

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

+12-4
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

+10
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,7 @@ export class WorkspaceStarter {
20332033
workspace?: Workspace,
20342034
instance?: WorkspaceInstance,
20352035
region?: WorkspaceRegion,
2036+
organizationId?: string,
20362037
) {
20372038
const req = new ResolveBaseImageRequest();
20382039
req.setRef(imageRef);
@@ -2041,6 +2042,15 @@ export class WorkspaceStarter {
20412042
const auth = new BuildRegistryAuth();
20422043
auth.setTotal(allowAll);
20432044
req.setAuth(auth);
2045+
2046+
// if the image resolution is for an organization, we also include the organization's set up env vars
2047+
if (organizationId) {
2048+
const envVars = await this.envVarService.listOrgEnvVarsWithValues(user.id, organizationId);
2049+
2050+
const additionalAuth = await this.getAdditionalImageAuth({ workspace: envVars });
2051+
additionalAuth.forEach((val, key) => auth.getAdditionalMap().set(key, val));
2052+
}
2053+
20442054
const client = await this.getImageBuilderClient(user, workspace, instance, region);
20452055
return client.resolveBaseImage({ span: ctx.span }, req);
20462056
}

0 commit comments

Comments
 (0)