Skip to content

Commit b195590

Browse files
committed
[supervisor] fix open access control not working when git permission missed
- Update `runAsGitpodUser` to append correct env - Fix .gitignore make whole supervisor component unsearchable
1 parent e01ca57 commit b195590

File tree

3 files changed

+48
-56
lines changed

3 files changed

+48
-56
lines changed

components/supervisor/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
supervisor
1+
/supervisor

components/supervisor/pkg/supervisor/git.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import (
1010
"os/exec"
1111
"strings"
1212

13+
"github.com/gitpod-io/gitpod/common-go/log"
1314
gitpod "github.com/gitpod-io/gitpod/gitpod-protocol"
1415
"github.com/gitpod-io/gitpod/supervisor/api"
1516
"github.com/gitpod-io/gitpod/supervisor/pkg/serverapi"
17+
"golang.org/x/xerrors"
1618
)
1719

1820
// GitTokenProvider provides tokens for Git hosting services by asking
@@ -62,22 +64,11 @@ func (p *GitTokenProvider) GetToken(ctx context.Context, req *api.GetTokenReques
6264
return nil, err
6365
}
6466
if result.Action == "Open Access Control" {
65-
gpPath, err := exec.LookPath("gp")
66-
if err != nil {
67-
return nil, err
68-
}
69-
gpCmd := exec.Command(gpPath, "preview", "--external", p.workspaceConfig.GitpodHost+"/access-control")
70-
gpCmd = runAsGitpodUser(gpCmd)
71-
err = gpCmd.Start()
72-
if err != nil {
73-
return nil, err
74-
}
75-
err = gpCmd.Process.Release()
76-
if err != nil {
77-
return nil, err
78-
}
67+
go func() {
68+
_ = p.openAccessControl()
69+
}()
7970
}
80-
return nil, nil
71+
return nil, xerrors.Errorf("miss required permissions")
8172
}
8273
tkn = &Token{
8374
User: token.Username,
@@ -89,6 +80,20 @@ func (p *GitTokenProvider) GetToken(ctx context.Context, req *api.GetTokenReques
8980
return tkn, nil
9081
}
9182

83+
func (p *GitTokenProvider) openAccessControl() error {
84+
gpPath, err := exec.LookPath("gp")
85+
if err != nil {
86+
return err
87+
}
88+
gpCmd := exec.Command(gpPath, "preview", "--external", p.workspaceConfig.GitpodHost+"/access-control")
89+
runAsGitpodUser(gpCmd)
90+
if b, err := gpCmd.CombinedOutput(); err != nil {
91+
log.WithField("Stdout", string(b)).WithError(err).Error("failed to exec gp preview to open access control")
92+
return err
93+
}
94+
return nil
95+
}
96+
9297
func getMissingScopes(required []string, provided map[string]struct{}) []string {
9398
var missing []string
9499
for _, r := range required {

components/supervisor/pkg/supervisor/supervisor.go

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ func (s IDEKind) String() string {
149149
return "unknown"
150150
}
151151

152+
var childProcEnvvars []string
153+
152154
// Run serves as main entrypoint to the supervisor.
153155
func Run(options ...RunOption) {
154156
exitCode := 0
@@ -182,15 +184,15 @@ func Run(options ...RunOption) {
182184

183185
// BEWARE: we can only call buildChildProcEnv once, because it might download env vars from a one-time-secret
184186
// URL, which would fail if we tried another time.
185-
childProcEnvvars := buildChildProcEnv(cfg, nil, opts.RunGP)
187+
childProcEnvvars = buildChildProcEnv(cfg, nil, opts.RunGP)
186188

187189
err = AddGitpodUserIfNotExists()
188190
if err != nil {
189191
log.WithError(err).Fatal("cannot ensure Gitpod user exists")
190192
}
191193
symlinkBinaries(cfg)
192194

193-
configureGit(cfg, childProcEnvvars)
195+
configureGit(cfg)
194196

195197
telemetry := analytics.NewFromEnvironment()
196198
defer telemetry.Close()
@@ -365,15 +367,15 @@ func Run(options ...RunOption) {
365367
if !cfg.isPrebuild() {
366368
// We need to checkout dotfiles first, because they may be changing the path which affects the IDE.
367369
// TODO(cw): provide better feedback if the IDE start fails because of the dotfiles (provide any feedback at all).
368-
installDotfiles(ctx, cfg, tokenService, childProcEnvvars)
370+
installDotfiles(ctx, cfg, tokenService)
369371
}
370372

371373
var ideWG sync.WaitGroup
372374
ideWG.Add(1)
373-
go startAndWatchIDE(ctx, cfg, &cfg.IDE, childProcEnvvars, &ideWG, cstate, ideReady, WebIDE, supervisorMetrics)
375+
go startAndWatchIDE(ctx, cfg, &cfg.IDE, &ideWG, cstate, ideReady, WebIDE, supervisorMetrics)
374376
if cfg.DesktopIDE != nil {
375377
ideWG.Add(1)
376-
go startAndWatchIDE(ctx, cfg, cfg.DesktopIDE, childProcEnvvars, &ideWG, cstate, desktopIdeReady, DesktopIDE, supervisorMetrics)
378+
go startAndWatchIDE(ctx, cfg, cfg.DesktopIDE, &ideWG, cstate, desktopIdeReady, DesktopIDE, supervisorMetrics)
377379
}
378380

379381
var (
@@ -394,7 +396,7 @@ func Run(options ...RunOption) {
394396
go startAPIEndpoint(ctx, cfg, &wg, apiServices, tunneledPortsService, metricsReporter, apiEndpointOpts...)
395397

396398
wg.Add(1)
397-
go startSSHServer(ctx, cfg, &wg, childProcEnvvars)
399+
go startSSHServer(ctx, cfg, &wg)
398400

399401
wg.Add(1)
400402
tasksSuccessChan := make(chan taskSuccess, 1)
@@ -435,12 +437,11 @@ func Run(options ...RunOption) {
435437
log.Debugf("unshallow of local repository took %v", time.Since(start))
436438
}()
437439

438-
if !isShallowRepository(repoRoot, childProcEnvvars) {
440+
if !isShallowRepository(repoRoot) {
439441
return
440442
}
441443

442444
cmd := runAsGitpodUser(exec.Command("git", "fetch", "--unshallow", "--tags"))
443-
cmd.Env = childProcEnvvars
444445
cmd.Dir = repoRoot
445446
cmd.Stdout = os.Stdout
446447
cmd.Stderr = os.Stderr
@@ -475,9 +476,8 @@ func Run(options ...RunOption) {
475476
wg.Wait()
476477
}
477478

478-
func isShallowRepository(rootDir string, env []string) bool {
479+
func isShallowRepository(rootDir string) bool {
479480
cmd := runAsGitpodUser(exec.Command("git", "rev-parse", "--is-shallow-repository"))
480-
cmd.Env = env
481481
cmd.Dir = rootDir
482482
out, err := cmd.CombinedOutput()
483483
if err != nil {
@@ -494,7 +494,7 @@ func isShallowRepository(rootDir string, env []string) bool {
494494
return isShallow
495495
}
496496

497-
func installDotfiles(ctx context.Context, cfg *Config, tokenService *InMemoryTokenService, childProcEnvvars []string) {
497+
func installDotfiles(ctx context.Context, cfg *Config, tokenService *InMemoryTokenService) {
498498
repo := cfg.DotfileRepo
499499
if repo == "" {
500500
return
@@ -509,15 +509,7 @@ func installDotfiles(ctx context.Context, cfg *Config, tokenService *InMemoryTok
509509
prep := func(cfg *Config, out io.Writer, name string, args ...string) *exec.Cmd {
510510
cmd := exec.Command(name, args...)
511511
cmd.Dir = "/home/gitpod"
512-
cmd.Env = childProcEnvvars
513-
cmd.SysProcAttr = &syscall.SysProcAttr{
514-
// All supervisor children run as gitpod user. The environment variables we produce are also
515-
// gitpod user specific.
516-
Credential: &syscall.Credential{
517-
Uid: gitpodUID,
518-
Gid: gitpodGID,
519-
},
520-
}
512+
runAsGitpodUser(cmd)
521513
cmd.Stdout = out
522514
cmd.Stderr = out
523515
return cmd
@@ -706,7 +698,7 @@ func symlinkBinaries(cfg *Config) {
706698
}
707699
}
708700

709-
func configureGit(cfg *Config, childProcEnvvars []string) {
701+
func configureGit(cfg *Config) {
710702
settings := [][]string{
711703
{"push.default", "simple"},
712704
{"alias.lg", "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"},
@@ -723,7 +715,6 @@ func configureGit(cfg *Config, childProcEnvvars []string) {
723715
for _, s := range settings {
724716
cmd := exec.Command("git", append([]string{"config", "--global"}, s...)...)
725717
cmd = runAsGitpodUser(cmd)
726-
cmd.Env = childProcEnvvars
727718
cmd.Stdout = os.Stdout
728719
cmd.Stderr = os.Stderr
729720
err := cmd.Run()
@@ -768,7 +759,7 @@ var (
768759
errSignalTerminated = errors.New("signal: terminated")
769760
)
770761

771-
func startAndWatchIDE(ctx context.Context, cfg *Config, ideConfig *IDEConfig, childProcEnvvars []string, wg *sync.WaitGroup, cstate *InMemoryContentState, ideReady *ideReadyState, ide IDEKind, metrics *metrics.SupervisorMetrics) {
762+
func startAndWatchIDE(ctx context.Context, cfg *Config, ideConfig *IDEConfig, wg *sync.WaitGroup, cstate *InMemoryContentState, ideReady *ideReadyState, ide IDEKind, metrics *metrics.SupervisorMetrics) {
772763
defer wg.Done()
773764
defer log.WithField("ide", ide.String()).Debug("startAndWatchIDE shutdown")
774765

@@ -795,7 +786,7 @@ supervisorLoop:
795786

796787
ideStopped = make(chan struct{}, 1)
797788
startTime := time.Now()
798-
cmd = prepareIDELaunch(cfg, ideConfig, childProcEnvvars)
789+
cmd = prepareIDELaunch(cfg, ideConfig)
799790
launchIDE(cfg, ideConfig, cmd, ideStopped, ideReady, &ideStatus, ide)
800791

801792
if firstStart {
@@ -896,7 +887,7 @@ func launchIDE(cfg *Config, ideConfig *IDEConfig, cmd *exec.Cmd, ideStopped chan
896887
}()
897888
}
898889

899-
func prepareIDELaunch(cfg *Config, ideConfig *IDEConfig, childProcEnvvars []string) *exec.Cmd {
890+
func prepareIDELaunch(cfg *Config, ideConfig *IDEConfig) *exec.Cmd {
900891
args := ideConfig.EntrypointArgs
901892
for i := range args {
902893
args[i] = strings.ReplaceAll(args[i], "{IDEPORT}", strconv.Itoa(cfg.IDEPort))
@@ -905,20 +896,15 @@ func prepareIDELaunch(cfg *Config, ideConfig *IDEConfig, childProcEnvvars []stri
905896
log.WithField("args", args).WithField("entrypoint", ideConfig.Entrypoint).Info("preparing IDE launch")
906897

907898
cmd := exec.Command(ideConfig.Entrypoint, args...)
908-
cmd.SysProcAttr = &syscall.SysProcAttr{
909-
// We need the child process to run in its own process group, s.t. we can suspend and resume
910-
// IDE and its children.
911-
Setpgid: true,
912-
Pdeathsig: syscall.SIGKILL,
913-
914-
// All supervisor children run as gitpod user. The environment variables we produce are also
915-
// gitpod user specific.
916-
Credential: &syscall.Credential{
917-
Uid: gitpodUID,
918-
Gid: gitpodGID,
919-
},
920-
}
921-
cmd.Env = childProcEnvvars
899+
900+
// All supervisor children run as gitpod user. The environment variables we produce are also
901+
// gitpod user specific.
902+
runAsGitpodUser(cmd)
903+
904+
// We need the child process to run in its own process group, s.t. we can suspend and resume
905+
// IDE and its children.
906+
cmd.SysProcAttr.Setpgid = true
907+
cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL
922908

923909
// Here we must resist the temptation to "neaten up" the IDE output for headless builds.
924910
// This would break the JSON parsing of the headless builds.
@@ -1384,7 +1370,7 @@ func stopWhenTasksAreDone(ctx context.Context, wg *sync.WaitGroup, shutdown chan
13841370
shutdown <- ShutdownReasonSuccess
13851371
}
13861372

1387-
func startSSHServer(ctx context.Context, cfg *Config, wg *sync.WaitGroup, childProcEnvvars []string) {
1373+
func startSSHServer(ctx context.Context, cfg *Config, wg *sync.WaitGroup) {
13881374
defer wg.Done()
13891375

13901376
if cfg.isHeadless() {
@@ -1783,6 +1769,7 @@ func runAsGitpodUser(cmd *exec.Cmd) *exec.Cmd {
17831769
if cmd.SysProcAttr.Credential == nil {
17841770
cmd.SysProcAttr.Credential = &syscall.Credential{}
17851771
}
1772+
cmd.Env = append(cmd.Env, childProcEnvvars...)
17861773
cmd.SysProcAttr.Credential.Uid = gitpodUID
17871774
cmd.SysProcAttr.Credential.Gid = gitpodGID
17881775
return cmd

0 commit comments

Comments
 (0)