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
26 changes: 18 additions & 8 deletions cmd/sciontool/commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -1002,14 +1002,8 @@ func gitCloneWorkspace(uid, gid int, agentHome string) error {
}
}

// Ensure the workspace directory is owned by the target user when running
// as root. Non-root containers cannot chown, and Kubernetes pods may
// already be running as the correct user/group via securityContext.
if uid > 0 && os.Getuid() == 0 {
if err := os.Chown(workspacePath, uid, gid); err != nil {
log.Error("Failed to chown workspace to UID=%d GID=%d: %v", uid, gid, err)
}
}
currentEUID := os.Geteuid()
ensureWorkspaceOwnership(workspacePath, uid, gid, currentEUID, os.Chown)

token := os.Getenv("GITHUB_TOKEN")
branch := os.Getenv("SCION_GIT_BRANCH")
Expand Down Expand Up @@ -1223,6 +1217,22 @@ func gitCloneWorkspace(uid, gid int, agentHome string) error {
return nil
}

func ensureWorkspaceOwnership(workspacePath string, uid, gid, currentEUID int, chown func(string, int, int) error) {
// Only root can successfully chown a mounted workspace. In restricted
// Kubernetes pods the init process may already be running as the scion
// user, so attempting chown here just adds noise before git init.
if uid <= 0 {
return
}
if currentEUID != 0 {
log.Info("Skipping workspace chown for %s; running as non-root UID=%d", workspacePath, currentEUID)
return
}
if err := chown(workspacePath, uid, gid); err != nil {
log.Error("Failed to chown workspace to UID=%d GID=%d: %v", uid, gid, err)
}
}

// configureSharedWorkspaceGit sets up git credentials for shared-workspace
// (git-workspace hybrid) groves. The workspace is a pre-cloned git repo shared
// by all agents; each agent gets its own credential helper in $HOME/.gitconfig
Expand Down
32 changes: 31 additions & 1 deletion cmd/sciontool/commands/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,6 @@ func TestGitCloneWorkspace_NonZeroUIDChownsWorkspace(t *testing.T) {
t.Errorf("expected a git failure error, got: %v", err)
}
}

func TestConfigureGitCommand_SkipsCredentialOverrideWhenAlreadyRunningAsTargetUser(t *testing.T) {
cmd := exec.CommandContext(context.Background(), "git", "status")

Expand Down Expand Up @@ -774,3 +773,34 @@ func TestConfigureGitCommand_SkipsCredentialOverrideForNonRootDifferentTarget(t
t.Fatalf("expected no credential override for non-root process, got %#v", cmd.SysProcAttr)
}
}

func TestEnsureWorkspaceOwnership_SkipsChownWhenNonRoot(t *testing.T) {
chownCalled := false
chown := func(string, int, int) error {
chownCalled = true
return nil
}

ensureWorkspaceOwnership("/workspace", 1000, 1000, 1000, chown)

if chownCalled {
t.Fatal("expected chown to be skipped when already running as non-root")
}
}

func TestEnsureWorkspaceOwnership_ChownsWhenRoot(t *testing.T) {
var gotPath string
var gotUID, gotGID int
chown := func(path string, uid, gid int) error {
gotPath = path
gotUID = uid
gotGID = gid
return nil
}

ensureWorkspaceOwnership("/workspace", 1000, 1000, 0, chown)

if gotPath != "/workspace" || gotUID != 1000 || gotGID != 1000 {
t.Fatalf("unexpected chown call: path=%q uid=%d gid=%d", gotPath, gotUID, gotGID)
}
}