Skip to content

Commit 260497b

Browse files
authored
[supervisor] fix open access control not working when git permission missed (#16987)
- Update `runAsGitpodUser` to append correct env - Fix .gitignore make whole supervisor component unsearchable
1 parent b84a256 commit 260497b

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()
@@ -366,15 +368,15 @@ func Run(options ...RunOption) {
366368
if !cfg.isPrebuild() {
367369
// We need to checkout dotfiles first, because they may be changing the path which affects the IDE.
368370
// TODO(cw): provide better feedback if the IDE start fails because of the dotfiles (provide any feedback at all).
369-
installDotfiles(ctx, cfg, tokenService, childProcEnvvars)
371+
installDotfiles(ctx, cfg, tokenService)
370372
}
371373

372374
var ideWG sync.WaitGroup
373375
ideWG.Add(1)
374-
go startAndWatchIDE(ctx, cfg, &cfg.IDE, childProcEnvvars, &ideWG, cstate, ideReady, WebIDE, supervisorMetrics)
376+
go startAndWatchIDE(ctx, cfg, &cfg.IDE, &ideWG, cstate, ideReady, WebIDE, supervisorMetrics)
375377
if cfg.DesktopIDE != nil {
376378
ideWG.Add(1)
377-
go startAndWatchIDE(ctx, cfg, cfg.DesktopIDE, childProcEnvvars, &ideWG, cstate, desktopIdeReady, DesktopIDE, supervisorMetrics)
379+
go startAndWatchIDE(ctx, cfg, cfg.DesktopIDE, &ideWG, cstate, desktopIdeReady, DesktopIDE, supervisorMetrics)
378380
}
379381

380382
var (
@@ -395,7 +397,7 @@ func Run(options ...RunOption) {
395397
go startAPIEndpoint(ctx, cfg, &wg, apiServices, tunneledPortsService, metricsReporter, apiEndpointOpts...)
396398

397399
wg.Add(1)
398-
go startSSHServer(ctx, cfg, &wg, childProcEnvvars)
400+
go startSSHServer(ctx, cfg, &wg)
399401

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

439-
if !isShallowRepository(repoRoot, childProcEnvvars) {
441+
if !isShallowRepository(repoRoot) {
440442
return
441443
}
442444

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

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

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

710-
func configureGit(cfg *Config, childProcEnvvars []string) {
702+
func configureGit(cfg *Config) {
711703
settings := [][]string{
712704
{"push.default", "simple"},
713705
{"alias.lg", "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"},
@@ -724,7 +716,6 @@ func configureGit(cfg *Config, childProcEnvvars []string) {
724716
for _, s := range settings {
725717
cmd := exec.Command("git", append([]string{"config", "--global"}, s...)...)
726718
cmd = runAsGitpodUser(cmd)
727-
cmd.Env = childProcEnvvars
728719
cmd.Stdout = os.Stdout
729720
cmd.Stderr = os.Stderr
730721
err := cmd.Run()
@@ -769,7 +760,7 @@ var (
769760
errSignalTerminated = errors.New("signal: terminated")
770761
)
771762

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

@@ -796,7 +787,7 @@ supervisorLoop:
796787

797788
ideStopped = make(chan struct{}, 1)
798789
startTime := time.Now()
799-
cmd = prepareIDELaunch(cfg, ideConfig, childProcEnvvars)
790+
cmd = prepareIDELaunch(cfg, ideConfig)
800791
launchIDE(cfg, ideConfig, cmd, ideStopped, ideReady, &ideStatus, ide)
801792

802793
if firstStart {
@@ -897,7 +888,7 @@ func launchIDE(cfg *Config, ideConfig *IDEConfig, cmd *exec.Cmd, ideStopped chan
897888
}()
898889
}
899890

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

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

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

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

13911377
if cfg.isHeadless() {
@@ -1784,6 +1770,7 @@ func runAsGitpodUser(cmd *exec.Cmd) *exec.Cmd {
17841770
if cmd.SysProcAttr.Credential == nil {
17851771
cmd.SysProcAttr.Credential = &syscall.Credential{}
17861772
}
1773+
cmd.Env = append(cmd.Env, childProcEnvvars...)
17871774
cmd.SysProcAttr.Credential.Uid = gitpodUID
17881775
cmd.SysProcAttr.Credential.Gid = gitpodGID
17891776
return cmd

0 commit comments

Comments
 (0)