Skip to content

Commit 810f5e9

Browse files
[WS CLI] Make env --scope=user compatible with GitLab groups (#20279)
* [WS CLI] Make `env --scope=user` compatible with GitLab groups * Allow updating `*/*` scoped vars for backwards compat * Fix test races
1 parent 45b822f commit 810f5e9

File tree

3 files changed

+48
-13
lines changed

3 files changed

+48
-13
lines changed

components/gitpod-cli/cmd/env.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ var scope = string(envScopeRepo)
3434
type envScope string
3535

3636
var (
37-
envScopeRepo envScope = "repo"
38-
envScopeUser envScope = "user"
37+
envScopeRepo envScope = "repo"
38+
envScopeUser envScope = "user"
39+
envScopeLegacyUser envScope = "legacy-user"
3940
)
4041

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

149150
operations := "create/get/update/delete"
150151
if options != nil && options.setEnvScope == envScopeUser {
152+
// Updating user env vars requires a different token with a special scope
153+
repositoryPattern = "*/**"
154+
operations = "update"
155+
}
156+
if options != nil && options.setEnvScope == envScopeLegacyUser {
151157
// Updating user env vars requires a different token with a special scope
152158
repositoryPattern = "*/*"
153159
operations = "update"
@@ -228,11 +234,25 @@ func setEnvs(ctx context.Context, setEnvScope envScope, args []string) error {
228234
err = result.client.SetEnvVar(ctx, v)
229235
if err != nil {
230236
if ferr, ok := err.(*jsonrpc2.Error); ok && ferr.Code == http.StatusForbidden && setEnvScope == envScopeUser {
231-
return fmt.Errorf(""+
232-
"Can't automatically create env var `%s` for security reasons.\n"+
233-
"Please create the var manually under %s/user/variables using Name=%s, Scope=*/*, Value=foobar", v.Name, result.gitpodHost, v.Name)
237+
// If we tried updating an env var with */** and it doesn't exist, it may exist with the */* scope
238+
options.setEnvScope = envScopeLegacyUser
239+
result, err := connectToServer(ctx, &options)
240+
if err != nil {
241+
return err
242+
}
243+
defer result.client.Close()
244+
245+
v.RepositoryPattern = "*/*"
246+
err = result.client.SetEnvVar(ctx, v)
247+
if ferr, ok := err.(*jsonrpc2.Error); ok && ferr.Code == http.StatusForbidden {
248+
fmt.Println(ferr.Message, ferr.Data)
249+
return fmt.Errorf(""+
250+
"Can't automatically create env var `%s` for security reasons.\n"+
251+
"Please create the var manually under %s/user/variables using Name=%s, Scope=*/**, Value=foobar", v.Name, result.gitpodHost, v.Name)
252+
}
253+
} else {
254+
return err
234255
}
235-
return err
236256
}
237257
printVar(v.Name, v.Value, exportEnvs)
238258
return nil

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -681,13 +681,15 @@ describe("WorkspaceService", async () => {
681681
const svc = container.get(WorkspaceService);
682682
const db = container.get<WorkspaceDB>(WorkspaceDB);
683683
const today = new Date();
684-
const daysAgo = (days: number) => new Date(today.getTime() - 1000 * 60 * 60 * 24 * days);
684+
const daysAgo = (days: number, from = today) => new Date(from.getTime() - 1000 * 60 * 60 * 24 * days);
685685

686686
const ws = await createTestWorkspace(svc, org, owner, project);
687-
await db.storeInstance({
687+
await svc.updateDeletionEligibilityTime(owner.id, ws.id, true);
688+
const instance = await db.storeInstance({
688689
id: v4(),
689690
workspaceId: ws.id,
690-
creationTime: daysAgo(7).toISOString(),
691+
// tomorrow, because as of #20271 deletion eligibility times can't go backwards and those are set when creating a ws
692+
creationTime: daysAgo(-1).toISOString(),
691693
status: {
692694
conditions: {},
693695
phase: "stopped",
@@ -705,17 +707,19 @@ describe("WorkspaceService", async () => {
705707
const workspace = await svc.getWorkspace(owner.id, ws.id);
706708
expect(workspace).to.not.be.undefined;
707709
expect(workspace.workspace.deletionEligibilityTime).to.not.be.undefined;
708-
expect(workspace.workspace.deletionEligibilityTime).to.eq(daysAgo(7 - 14).toISOString());
710+
expect(workspace.workspace.deletionEligibilityTime).to.eq(
711+
daysAgo(-14, new Date(instance.creationTime)).toISOString(),
712+
);
709713
});
710714

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

717721
const ws = await createTestWorkspace(svc, org, owner, project);
718-
await db.storeInstance({
722+
const instance = await db.storeInstance({
719723
id: v4(),
720724
workspaceId: ws.id,
721725
creationTime: daysAgo(7).toISOString(),
@@ -739,7 +743,9 @@ describe("WorkspaceService", async () => {
739743
const workspace = await svc.getWorkspace(owner.id, ws.id);
740744
expect(workspace).to.not.be.undefined;
741745
expect(workspace.workspace.deletionEligibilityTime).to.not.be.undefined;
742-
expect(workspace.workspace.deletionEligibilityTime).to.eq(daysAgo(7 - 14 * 2).toISOString());
746+
expect(workspace.workspace.deletionEligibilityTime).to.eq(
747+
daysAgo(-14 * 2, new Date(instance.creationTime)).toISOString(),
748+
);
743749
});
744750

745751
it("should update the deletion eligibility time of a prebuild", async () => {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,15 @@ export class WorkspaceStarter {
17201720
);
17211721
}
17221722
// The only exception is "updates", which we allow to be made to all env vars (that exist).
1723+
scopes.push(
1724+
"resource:" +
1725+
ScopedResourceGuard.marshalResourceScope({
1726+
kind: "envVar",
1727+
subjectID: "*/**",
1728+
operations: ["update"],
1729+
}),
1730+
);
1731+
// For updating environment variables created with */* instead of */**, we fall back to updating those
17231732
scopes.push(
17241733
"resource:" +
17251734
ScopedResourceGuard.marshalResourceScope({

0 commit comments

Comments
 (0)