Skip to content

Commit d3eccd0

Browse files
authored
[gp] Allow update of existing user-scoped env vars (#20193)
* [gp, protocol, server] Remove references to long-deprecated "getEnvVars" API method * [gp, server] Allow users to update user-scopes env vars
1 parent 3fdfd12 commit d3eccd0

File tree

5 files changed

+63
-87
lines changed

5 files changed

+63
-87
lines changed

components/gitpod-cli/cmd/env.go

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ import (
2727

2828
var exportEnvs = false
2929
var unsetEnvs = false
30+
var scope = string(envScopeRepo)
31+
32+
type envScope string
33+
34+
var (
35+
envScopeRepo envScope = "repo"
36+
envScopeUser envScope = "user"
37+
)
3038

3139
// envCmd represents the env command
3240
var envCmd = &cobra.Command{
@@ -67,7 +75,8 @@ delete environment variables with a repository pattern of */foo, foo/* or */*.
6775
if unsetEnvs {
6876
err = deleteEnvs(ctx, args)
6977
} else {
70-
err = setEnvs(ctx, args)
78+
scopeUser := scope == string(envScopeUser)
79+
err = setEnvs(ctx, scopeUser, args)
7180
}
7281
} else {
7382
err = getEnvs(ctx)
@@ -80,14 +89,14 @@ type connectToServerResult struct {
8089
repositoryPattern string
8190
wsInfo *supervisorapi.WorkspaceInfoResponse
8291
client *serverapi.APIoverJSONRPC
83-
84-
useDeprecatedGetEnvVar bool
8592
}
8693

8794
type connectToServerOptions struct {
8895
supervisorClient *supervisor.SupervisorClient
8996
wsInfo *api.WorkspaceInfoResponse
9097
log *log.Entry
98+
99+
setEnvScopeUser bool
91100
}
92101

93102
func connectToServer(ctx context.Context, options *connectToServerOptions) (*connectToServerResult, error) {
@@ -123,31 +132,23 @@ func connectToServer(ctx context.Context, options *connectToServerOptions) (*con
123132
}
124133
repositoryPattern := wsinfo.Repository.Owner + "/" + wsinfo.Repository.Name
125134

126-
var useDeprecatedGetEnvVar bool
135+
operations := "create/get/update/delete"
136+
if options != nil && options.setEnvScopeUser {
137+
// Updating user env vars requires a different token with a special scope
138+
repositoryPattern = "*/*"
139+
operations = "update"
140+
}
141+
127142
clientToken, err := supervisorClient.Token.GetToken(ctx, &supervisorapi.GetTokenRequest{
128143
Host: wsinfo.GitpodApi.Host,
129144
Kind: "gitpod",
130145
Scope: []string{
131146
"function:getWorkspaceEnvVars",
132147
"function:setEnvVar",
133148
"function:deleteEnvVar",
134-
"resource:envVar::" + repositoryPattern + "::create/get/update/delete",
149+
"resource:envVar::" + repositoryPattern + "::" + operations,
135150
},
136151
})
137-
if err != nil {
138-
// TODO remove then GetWorkspaceEnvVars is deployed
139-
clientToken, err = supervisorClient.Token.GetToken(ctx, &supervisorapi.GetTokenRequest{
140-
Host: wsinfo.GitpodApi.Host,
141-
Kind: "gitpod",
142-
Scope: []string{
143-
"function:getEnvVars", // TODO remove then getWorkspaceEnvVars is deployed
144-
"function:setEnvVar",
145-
"function:deleteEnvVar",
146-
"resource:envVar::" + repositoryPattern + "::create/get/update/delete",
147-
},
148-
})
149-
useDeprecatedGetEnvVar = true
150-
}
151152
if err != nil {
152153
return nil, xerrors.Errorf("failed getting token from supervisor: %w", err)
153154
}
@@ -165,7 +166,7 @@ func connectToServer(ctx context.Context, options *connectToServerOptions) (*con
165166
if err != nil {
166167
return nil, xerrors.Errorf("failed connecting to server: %w", err)
167168
}
168-
return &connectToServerResult{repositoryPattern, wsinfo, client, useDeprecatedGetEnvVar}, nil
169+
return &connectToServerResult{repositoryPattern, wsinfo, client}, nil
169170
}
170171

171172
func getWorkspaceEnvs(ctx context.Context, options *connectToServerOptions) ([]*serverapi.EnvVar, error) {
@@ -175,10 +176,7 @@ func getWorkspaceEnvs(ctx context.Context, options *connectToServerOptions) ([]*
175176
}
176177
defer result.client.Close()
177178

178-
if !result.useDeprecatedGetEnvVar {
179-
return result.client.GetWorkspaceEnvVars(ctx, result.wsInfo.WorkspaceId)
180-
}
181-
return result.client.GetEnvVars(ctx)
179+
return result.client.GetWorkspaceEnvVars(ctx, result.wsInfo.WorkspaceId)
182180
}
183181

184182
func getEnvs(ctx context.Context) error {
@@ -194,8 +192,11 @@ func getEnvs(ctx context.Context) error {
194192
return nil
195193
}
196194

197-
func setEnvs(ctx context.Context, args []string) error {
198-
result, err := connectToServer(ctx, nil)
195+
func setEnvs(ctx context.Context, scopeUser bool, args []string) error {
196+
options := connectToServerOptions{
197+
setEnvScopeUser: scopeUser,
198+
}
199+
result, err := connectToServer(ctx, &options)
199200
if err != nil {
200201
return err
201202
}
@@ -291,4 +292,5 @@ func init() {
291292

292293
envCmd.Flags().BoolVarP(&exportEnvs, "export", "e", false, "produce a script that can be eval'ed in Bash")
293294
envCmd.Flags().BoolVarP(&unsetEnvs, "unset", "u", false, "deletes/unsets persisted environment variables")
295+
envCmd.Flags().StringVarP(&scope, "scope", "s", "repo", "deletes/unsets persisted environment variables")
294296
}

components/gitpod-cli/cmd/validate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie
238238
serverLog := logrus.NewEntry(logrus.New())
239239
serverLog.Logger.SetLevel(logLevel)
240240
setLoggerFormatter(serverLog.Logger)
241-
workspaceEnvs, err := getWorkspaceEnvs(ctx, &connectToServerOptions{supervisorClient, wsInfo, serverLog})
241+
workspaceEnvs, err := getWorkspaceEnvs(ctx, &connectToServerOptions{supervisorClient, wsInfo, serverLog, false})
242242
if err != nil {
243243
return err
244244
}

components/gitpod-protocol/go/gitpod-service.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ type APIInterface interface {
6161
ClosePort(ctx context.Context, workspaceID string, port float32) (err error)
6262
UpdateGitStatus(ctx context.Context, workspaceID string, status *WorkspaceInstanceRepoStatus) (err error)
6363
GetWorkspaceEnvVars(ctx context.Context, workspaceID string) (res []*EnvVar, err error)
64-
GetEnvVars(ctx context.Context) (res []*EnvVar, err error)
6564
SetEnvVar(ctx context.Context, variable *UserEnvVarValue) (err error)
6665
DeleteEnvVar(ctx context.Context, variable *UserEnvVarValue) (err error)
6766
HasSSHPublicKey(ctx context.Context) (res bool, err error)
@@ -179,8 +178,6 @@ const (
179178
FunctionOpenPort FunctionName = "openPort"
180179
// FunctionClosePort is the name of the closePort function
181180
FunctionClosePort FunctionName = "closePort"
182-
// FunctionGetEnvVars is the name of the getEnvVars function
183-
FunctionGetEnvVars FunctionName = "getEnvVars"
184181
// FunctionSetEnvVar is the name of the setEnvVar function
185182
FunctionSetEnvVar FunctionName = "setEnvVar"
186183
// FunctionDeleteEnvVar is the name of the deleteEnvVar function
@@ -1088,24 +1085,6 @@ func (gp *APIoverJSONRPC) GetWorkspaceEnvVars(ctx context.Context, workspaceID s
10881085
return
10891086
}
10901087

1091-
// GetEnvVars calls getEnvVars on the server
1092-
func (gp *APIoverJSONRPC) GetEnvVars(ctx context.Context) (res []*EnvVar, err error) {
1093-
if gp == nil {
1094-
err = errNotConnected
1095-
return
1096-
}
1097-
var _params []interface{}
1098-
1099-
var result []*EnvVar
1100-
err = gp.C.Call(ctx, "getEnvVars", _params, &result)
1101-
if err != nil {
1102-
return
1103-
}
1104-
res = result
1105-
1106-
return
1107-
}
1108-
11091088
// SetEnvVar calls setEnvVar on the server
11101089
func (gp *APIoverJSONRPC) SetEnvVar(ctx context.Context, variable *UserEnvVarValue) (err error) {
11111090
if gp == nil {

components/gitpod-protocol/go/mock.go

Lines changed: 23 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1616,7 +1616,6 @@ export class WorkspaceStarter {
16161616
"function:guessGitTokenScopes",
16171617
"function:updateGitStatus",
16181618
"function:getWorkspaceEnvVars",
1619-
"function:getEnvVars", // TODO remove this after new gitpod-cli is deployed
16201619
"function:setEnvVar",
16211620
"function:deleteEnvVar",
16221621
"function:getTeams",
@@ -1666,6 +1665,8 @@ export class WorkspaceStarter {
16661665
operations: ["create", "get"],
16671666
}),
16681667
];
1668+
// By intention, we only limit the token passed down to the workspace to the env vars scoped to that workspace.
1669+
// This is meant to maintain the "workspace as a unit of isolation" principle on the API level.
16691670
if (CommitContext.is(workspace.context)) {
16701671
const subjectID = workspace.context.repository.owner + "/" + workspace.context.repository.name;
16711672
scopes.push(
@@ -1677,6 +1678,15 @@ export class WorkspaceStarter {
16771678
}),
16781679
);
16791680
}
1681+
// The only exception is "updates", which we allow to be made to all env vars (that exist).
1682+
scopes.push(
1683+
"resource:" +
1684+
ScopedResourceGuard.marshalResourceScope({
1685+
kind: "envVar",
1686+
subjectID: "*/*",
1687+
operations: ["update"],
1688+
}),
1689+
);
16801690
return scopes;
16811691
}
16821692

0 commit comments

Comments
 (0)