Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions components/gitpod-cli/cmd/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ var scope = string(envScopeRepo)
type envScope string

var (
envScopeRepo envScope = "repo"
envScopeUser envScope = "user"
envScopeRepo envScope = "repo"
envScopeUser envScope = "user"
envScopeLegacyUser envScope = "legacy-user"
)

func envScopeFromString(s string) envScope {
Expand Down Expand Up @@ -148,6 +149,11 @@ func connectToServer(ctx context.Context, options *connectToServerOptions) (*con

operations := "create/get/update/delete"
if options != nil && options.setEnvScope == envScopeUser {
// Updating user env vars requires a different token with a special scope
repositoryPattern = "*/**"
operations = "update"
}
if options != nil && options.setEnvScope == envScopeLegacyUser {
// Updating user env vars requires a different token with a special scope
repositoryPattern = "*/*"
operations = "update"
Expand Down Expand Up @@ -228,11 +234,25 @@ func setEnvs(ctx context.Context, setEnvScope envScope, args []string) error {
err = result.client.SetEnvVar(ctx, v)
if err != nil {
if ferr, ok := err.(*jsonrpc2.Error); ok && ferr.Code == http.StatusForbidden && setEnvScope == envScopeUser {
return fmt.Errorf(""+
"Can't automatically create env var `%s` for security reasons.\n"+
"Please create the var manually under %s/user/variables using Name=%s, Scope=*/*, Value=foobar", v.Name, result.gitpodHost, v.Name)
// If we tried updating an env var with */** and it doesn't exist, it may exist with the */* scope
options.setEnvScope = envScopeLegacyUser
result, err := connectToServer(ctx, &options)
if err != nil {
return err
}
defer result.client.Close()

v.RepositoryPattern = "*/*"
err = result.client.SetEnvVar(ctx, v)
if ferr, ok := err.(*jsonrpc2.Error); ok && ferr.Code == http.StatusForbidden {
fmt.Println(ferr.Message, ferr.Data)
return fmt.Errorf(""+
"Can't automatically create env var `%s` for security reasons.\n"+
"Please create the var manually under %s/user/variables using Name=%s, Scope=*/**, Value=foobar", v.Name, result.gitpodHost, v.Name)
}
} else {
return err
}
return err
}
printVar(v.Name, v.Value, exportEnvs)
return nil
Expand Down
20 changes: 13 additions & 7 deletions components/server/src/workspace/workspace-service.spec.db.ts
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to update these because they were flaky. When we create a workspace, we update its deletion eligibility time asynchronously and that created races in the tests. Now we call svc.updateDeletionEligibilityTime explicitly and synchronously, so that we get rid of that possible variance.

Copy link
Member Author

@filiptronicek filiptronicek Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also base the test expectations off of the creationTime the instances are created with because otherwise we're comparing a date at the beginning of the test with a date at the end of it, which can cause trouble when we're at the edge of a millisecond. We could improve by not relying on the instance's creationTime and storing it ourselves separately, but this will do for now.

Original file line number Diff line number Diff line change
Expand Up @@ -681,13 +681,15 @@ describe("WorkspaceService", async () => {
const svc = container.get(WorkspaceService);
const db = container.get<WorkspaceDB>(WorkspaceDB);
const today = new Date();
const daysAgo = (days: number) => new Date(today.getTime() - 1000 * 60 * 60 * 24 * days);
const daysAgo = (days: number, from = today) => new Date(from.getTime() - 1000 * 60 * 60 * 24 * days);

const ws = await createTestWorkspace(svc, org, owner, project);
await db.storeInstance({
await svc.updateDeletionEligibilityTime(owner.id, ws.id, true);
const instance = await db.storeInstance({
id: v4(),
workspaceId: ws.id,
creationTime: daysAgo(7).toISOString(),
// tomorrow, because as of #20271 deletion eligibility times can't go backwards and those are set when creating a ws
creationTime: daysAgo(-1).toISOString(),
status: {
conditions: {},
phase: "stopped",
Expand All @@ -705,17 +707,19 @@ describe("WorkspaceService", async () => {
const workspace = await svc.getWorkspace(owner.id, ws.id);
expect(workspace).to.not.be.undefined;
expect(workspace.workspace.deletionEligibilityTime).to.not.be.undefined;
expect(workspace.workspace.deletionEligibilityTime).to.eq(daysAgo(7 - 14).toISOString());
expect(workspace.workspace.deletionEligibilityTime).to.eq(
daysAgo(-14, new Date(instance.creationTime)).toISOString(),
);
});

it("should update the deletion eligibility time of a workspace with git changes", async () => {
const svc = container.get(WorkspaceService);
const db = container.get<WorkspaceDB>(WorkspaceDB);
const today = new Date();
const daysAgo = (days: number) => new Date(today.getTime() - 1000 * 60 * 60 * 24 * days);
const daysAgo = (days: number, from = today) => new Date(from.getTime() - 1000 * 60 * 60 * 24 * days);

const ws = await createTestWorkspace(svc, org, owner, project);
await db.storeInstance({
const instance = await db.storeInstance({
id: v4(),
workspaceId: ws.id,
creationTime: daysAgo(7).toISOString(),
Expand All @@ -739,7 +743,9 @@ describe("WorkspaceService", async () => {
const workspace = await svc.getWorkspace(owner.id, ws.id);
expect(workspace).to.not.be.undefined;
expect(workspace.workspace.deletionEligibilityTime).to.not.be.undefined;
expect(workspace.workspace.deletionEligibilityTime).to.eq(daysAgo(7 - 14 * 2).toISOString());
expect(workspace.workspace.deletionEligibilityTime).to.eq(
daysAgo(-14 * 2, new Date(instance.creationTime)).toISOString(),
);
});

it("should update the deletion eligibility time of a prebuild", async () => {
Expand Down
9 changes: 9 additions & 0 deletions components/server/src/workspace/workspace-starter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,15 @@ export class WorkspaceStarter {
);
}
// The only exception is "updates", which we allow to be made to all env vars (that exist).
scopes.push(
"resource:" +
ScopedResourceGuard.marshalResourceScope({
kind: "envVar",
subjectID: "*/**",
operations: ["update"],
}),
);
// For updating environment variables created with */* instead of */**, we fall back to updating those
scopes.push(
"resource:" +
ScopedResourceGuard.marshalResourceScope({
Expand Down
Loading