From e98ce9725afd560e5a0e4eae49ef715a70056df3 Mon Sep 17 00:00:00 2001 From: Martin Rudat Date: Sun, 26 Oct 2025 10:33:42 +0000 Subject: [PATCH 1/6] from https://github.com/loft-sh/devpod/issues/1476#issue-2739087709 --- pkg/docker/helper.go | 9 +++++++++ pkg/driver/docker/docker.go | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/pkg/docker/helper.go b/pkg/docker/helper.go index 517020d3e..53ae8a7ec 100644 --- a/pkg/docker/helper.go +++ b/pkg/docker/helper.go @@ -67,6 +67,15 @@ func (r *DockerHelper) GPUSupportEnabled() (bool, error) { return strings.Contains(string(out), "nvidia-container-runtime"), nil } +func (r *DockerHelper) SELinuxEnabled(ctx context.Context) (bool, error) { + out, err := r.buildCmd(ctx, "info", "-f", "{{.Host.Security.SELinuxEnabled}}").Output() + if err != nil { + return false, command.WrapCommandError(out, err) + } + + return strings.Contains(string(out), "true"), nil +} + func (r *DockerHelper) FindDevContainer(ctx context.Context, labels []string) (*config.ContainerDetails, error) { containers, err := r.FindContainer(ctx, labels) if err != nil { diff --git a/pkg/driver/docker/docker.go b/pkg/driver/docker/docker.go index 36a7fa595..c200e8e7c 100644 --- a/pkg/driver/docker/docker.go +++ b/pkg/driver/docker/docker.go @@ -273,6 +273,12 @@ func (d *dockerDriver) RunDockerDevContainer( mountPath = strings.Replace(mountPath, ",consistency='consistent'", "", 1) } + if ok, err := helper.SELinuxEnabled(ctx); ok && err == nil { + mountPath = fmt.Sprintf("%s,z", mountPath) + } else if err != nil { + d.Log.Infof("Unable to check if docker is running with SELinux. Assuming it is not.") + } + args = append(args, "--mount", mountPath) } From 65551cb70c95771cd655202e25d4111323f864b8 Mon Sep 17 00:00:00 2001 From: Martin Rudat Date: Sun, 26 Oct 2025 11:32:24 +0000 Subject: [PATCH 2/6] Not enough magic. --- cmd/up.go | 5 +++++ pkg/config/context.go | 7 +++++++ pkg/driver/docker/docker.go | 1 + 3 files changed, 13 insertions(+) diff --git a/cmd/up.go b/cmd/up.go index 148a167c2..3f85f2790 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -64,6 +64,7 @@ type UpCmd struct { GPGAgentForwarding bool OpenIDE bool Reconfigure bool + DisableSELinuxFlag bool SSHConfigPath string @@ -90,6 +91,9 @@ func NewUpCmd(f *flags.GlobalFlags) *cobra.Command { if devPodConfig.ContextOption(config.ContextOptionSSHStrictHostKeyChecking) == "true" { cmd.StrictHostKeyChecking = true } + if devPodConfig.ContextOption(config.ContextOptionDisableSELinuxFlag) == "true" { + cmd.DisableSELinuxFlag = true + } ctx, cancel := WithSignals(cobraCmd.Context()) defer cancel() @@ -117,6 +121,7 @@ func NewUpCmd(f *flags.GlobalFlags) *cobra.Command { upCmd.Flags().BoolVar(&cmd.Reconfigure, "reconfigure", false, "Reconfigure the options for this workspace. Only supported in DevPod Pro right now.") upCmd.Flags().BoolVar(&cmd.Recreate, "recreate", false, "If true will remove any existing containers and recreate them") upCmd.Flags().BoolVar(&cmd.Reset, "reset", false, "If true will remove any existing containers including sources, and recreate them") + upCmd.Flags().BoolVar(&cmd.DisableSELinuxFlag, "disable-selinux-flag", false, "If true will add a :z suffix to all volume mounts to disable SELinux enforcement issues") upCmd.Flags().StringSliceVar(&cmd.PrebuildRepositories, "prebuild-repository", []string{}, "Docker repository that hosts devpod prebuilds for this workspace") upCmd.Flags().StringArrayVar(&cmd.WorkspaceEnv, "workspace-env", []string{}, "Extra env variables to put into the workspace. E.g. MY_ENV_VAR=MY_VALUE") upCmd.Flags().StringSliceVar(&cmd.WorkspaceEnvFile, "workspace-env-file", []string{}, "The path to files containing a list of extra env variables to put into the workspace. E.g. MY_ENV_VAR=MY_VALUE") diff --git a/pkg/config/context.go b/pkg/config/context.go index d629a68f2..a7771bf80 100644 --- a/pkg/config/context.go +++ b/pkg/config/context.go @@ -22,6 +22,7 @@ const ( ContextOptionAgentInjectTimeout = "AGENT_INJECT_TIMEOUT" ContextOptionRegistryCache = "REGISTRY_CACHE" ContextOptionSSHStrictHostKeyChecking = "SSH_STRICT_HOST_KEY_CHECKING" + ContextOptionDisableSELinuxFlag = "DISABLE_SELINUX_FLAG" ) var ContextOptions = []ContextOption{ @@ -105,6 +106,12 @@ var ContextOptions = []ContextOption{ Default: "false", Enum: []string{"true", "false"}, }, + { + Name: ContextOptionDisableSELinuxFlag, + Description: "Enables adding the :z suffix to volume mounts to avoid SELinux enforcement issues", + Default: "false", + Enum: []string{"true", "false"}, + }, } func MergeContextOptions(contextConfig *ContextConfig, environ []string) { diff --git a/pkg/driver/docker/docker.go b/pkg/driver/docker/docker.go index c200e8e7c..a97647bdd 100644 --- a/pkg/driver/docker/docker.go +++ b/pkg/driver/docker/docker.go @@ -273,6 +273,7 @@ func (d *dockerDriver) RunDockerDevContainer( mountPath = strings.Replace(mountPath, ",consistency='consistent'", "", 1) } + // TODO somehow store DisableSELinuxFlag in options? if ok, err := helper.SELinuxEnabled(ctx); ok && err == nil { mountPath = fmt.Sprintf("%s,z", mountPath) } else if err != nil { From 35acad0ba10121d02e01e2c296f0420a17a345bc Mon Sep 17 00:00:00 2001 From: Martin Rudat Date: Sun, 26 Oct 2025 22:47:49 +1100 Subject: [PATCH 3/6] Fix the description; it only touches the workspace mount. --- cmd/up.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/up.go b/cmd/up.go index 3f85f2790..83eb25d5b 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -121,7 +121,7 @@ func NewUpCmd(f *flags.GlobalFlags) *cobra.Command { upCmd.Flags().BoolVar(&cmd.Reconfigure, "reconfigure", false, "Reconfigure the options for this workspace. Only supported in DevPod Pro right now.") upCmd.Flags().BoolVar(&cmd.Recreate, "recreate", false, "If true will remove any existing containers and recreate them") upCmd.Flags().BoolVar(&cmd.Reset, "reset", false, "If true will remove any existing containers including sources, and recreate them") - upCmd.Flags().BoolVar(&cmd.DisableSELinuxFlag, "disable-selinux-flag", false, "If true will add a :z suffix to all volume mounts to disable SELinux enforcement issues") + upCmd.Flags().BoolVar(&cmd.DisableSELinuxFlag, "disable-selinux-flag", false, "If true will add a :z suffix to the workspace mount to disable SELinux enforcement issues") upCmd.Flags().StringSliceVar(&cmd.PrebuildRepositories, "prebuild-repository", []string{}, "Docker repository that hosts devpod prebuilds for this workspace") upCmd.Flags().StringArrayVar(&cmd.WorkspaceEnv, "workspace-env", []string{}, "Extra env variables to put into the workspace. E.g. MY_ENV_VAR=MY_VALUE") upCmd.Flags().StringSliceVar(&cmd.WorkspaceEnvFile, "workspace-env-file", []string{}, "The path to files containing a list of extra env variables to put into the workspace. E.g. MY_ENV_VAR=MY_VALUE") From 442fe6d64dafdb49fa761101fc0b81f6224ee1f5 Mon Sep 17 00:00:00 2001 From: Martin Rudat Date: Sun, 26 Oct 2025 12:04:21 +0000 Subject: [PATCH 4/6] Improve the description... I think? --- cmd/up.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/up.go b/cmd/up.go index 83eb25d5b..d68cd8ccf 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -121,7 +121,7 @@ func NewUpCmd(f *flags.GlobalFlags) *cobra.Command { upCmd.Flags().BoolVar(&cmd.Reconfigure, "reconfigure", false, "Reconfigure the options for this workspace. Only supported in DevPod Pro right now.") upCmd.Flags().BoolVar(&cmd.Recreate, "recreate", false, "If true will remove any existing containers and recreate them") upCmd.Flags().BoolVar(&cmd.Reset, "reset", false, "If true will remove any existing containers including sources, and recreate them") - upCmd.Flags().BoolVar(&cmd.DisableSELinuxFlag, "disable-selinux-flag", false, "If true will add a :z suffix to the workspace mount to disable SELinux enforcement issues") + upCmd.Flags().BoolVar(&cmd.DisableSELinuxFlag, "disable-selinux-flag", false, "If true will add the z flag to the workspace mount to disable SELinux") upCmd.Flags().StringSliceVar(&cmd.PrebuildRepositories, "prebuild-repository", []string{}, "Docker repository that hosts devpod prebuilds for this workspace") upCmd.Flags().StringArrayVar(&cmd.WorkspaceEnv, "workspace-env", []string{}, "Extra env variables to put into the workspace. E.g. MY_ENV_VAR=MY_VALUE") upCmd.Flags().StringSliceVar(&cmd.WorkspaceEnvFile, "workspace-env-file", []string{}, "The path to files containing a list of extra env variables to put into the workspace. E.g. MY_ENV_VAR=MY_VALUE") From b052f3730b3839ed20c54c0eca511bca31549931 Mon Sep 17 00:00:00 2001 From: Martin Rudat Date: Sun, 26 Oct 2025 12:17:45 +0000 Subject: [PATCH 5/6] Make the description match. --- pkg/config/context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/context.go b/pkg/config/context.go index a7771bf80..b42f857a2 100644 --- a/pkg/config/context.go +++ b/pkg/config/context.go @@ -108,7 +108,7 @@ var ContextOptions = []ContextOption{ }, { Name: ContextOptionDisableSELinuxFlag, - Description: "Enables adding the :z suffix to volume mounts to avoid SELinux enforcement issues", + Description: "Adds the z flag to the workspace mounts to disable SELinux", Default: "false", Enum: []string{"true", "false"}, }, From 3a8bcc6cab220a1280dfb3b6954f29d4fa7015f9 Mon Sep 17 00:00:00 2001 From: Martin Rudat Date: Sun, 26 Oct 2025 14:46:28 +0000 Subject: [PATCH 6/6] It builds, I guess? --- cmd/up.go | 1 - pkg/devcontainer/config.go | 1 + pkg/devcontainer/config/substitute.go | 1 + pkg/devcontainer/single.go | 33 +++++++++++++++------------ pkg/driver/docker/docker.go | 11 +++++---- pkg/driver/types.go | 3 +++ pkg/provider/workspace.go | 1 + 7 files changed, 30 insertions(+), 21 deletions(-) diff --git a/cmd/up.go b/cmd/up.go index d68cd8ccf..4c5da0615 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -64,7 +64,6 @@ type UpCmd struct { GPGAgentForwarding bool OpenIDE bool Reconfigure bool - DisableSELinuxFlag bool SSHConfigPath string diff --git a/pkg/devcontainer/config.go b/pkg/devcontainer/config.go index d4a172111..92af91a02 100644 --- a/pkg/devcontainer/config.go +++ b/pkg/devcontainer/config.go @@ -138,6 +138,7 @@ func (r *runner) substitute( parsedConfig.DockerfileContainer = config.DockerfileContainer{} parsedConfig.ImageContainer = config.ImageContainer{Image: options.DevContainerImage} } + substitutionContext.DisableSELinuxFlag = options.DisableSELinuxFlag parsedConfig.Origin = configFile return &config.SubstitutedConfig{ diff --git a/pkg/devcontainer/config/substitute.go b/pkg/devcontainer/config/substitute.go index 22945d170..080caddad 100644 --- a/pkg/devcontainer/config/substitute.go +++ b/pkg/devcontainer/config/substitute.go @@ -25,6 +25,7 @@ type SubstitutionContext struct { LocalWorkspaceFolder string `json:"LocalWorkspaceFolder,omitempty"` ContainerWorkspaceFolder string `json:"ContainerWorkspaceFolder,omitempty"` Env map[string]string `json:"Env,omitempty"` + DisableSELinuxFlag bool `json:"DisableSELinuxFlag,omitempty"` WorkspaceMount string `json:"WorkspaceMount,omitempty"` } diff --git a/pkg/devcontainer/single.go b/pkg/devcontainer/single.go index cfb123bfe..f4021c86b 100644 --- a/pkg/devcontainer/single.go +++ b/pkg/devcontainer/single.go @@ -183,6 +183,7 @@ func (r *runner) runContainer( } runOptions.Env = r.addExtraEnvVars(runOptions.Env) + runOptions.DisableSELinuxFlag = substitutionContext.DisableSELinuxFlag // check if docker dockerDriver, ok := r.Driver.(driver.DockerDriver) @@ -274,9 +275,10 @@ func (r *runner) getDockerlessRunOptions( metadata.ImageMetadataLabel + "=" + string(marshalled), config.UserLabel + "=" + buildInfo.Dockerless.User, }, - Privileged: mergedConfig.Privileged, - WorkspaceMount: &workspaceMountParsed, - Mounts: mounts, + Privileged: mergedConfig.Privileged, + WorkspaceMount: &workspaceMountParsed, + Mounts: mounts, + DisableSELinuxFlag: substitutionContext.DisableSELinuxFlag, }, nil } @@ -312,18 +314,19 @@ func (r *runner) getRunOptions( } return &driver.RunOptions{ - UID: uid, - Image: buildInfo.ImageName, - User: user, - Entrypoint: entrypoint, - Cmd: cmd, - Env: mergedConfig.ContainerEnv, - CapAdd: mergedConfig.CapAdd, - Labels: labels, - Privileged: mergedConfig.Privileged, - WorkspaceMount: &workspaceMountParsed, - SecurityOpt: mergedConfig.SecurityOpt, - Mounts: mergedConfig.Mounts, + UID: uid, + Image: buildInfo.ImageName, + User: user, + Entrypoint: entrypoint, + Cmd: cmd, + Env: mergedConfig.ContainerEnv, + CapAdd: mergedConfig.CapAdd, + Labels: labels, + Privileged: mergedConfig.Privileged, + WorkspaceMount: &workspaceMountParsed, + SecurityOpt: mergedConfig.SecurityOpt, + Mounts: mergedConfig.Mounts, + DisableSELinuxFlag: substitutionContext.DisableSELinuxFlag, }, nil } diff --git a/pkg/driver/docker/docker.go b/pkg/driver/docker/docker.go index a97647bdd..653a03b78 100644 --- a/pkg/driver/docker/docker.go +++ b/pkg/driver/docker/docker.go @@ -273,11 +273,12 @@ func (d *dockerDriver) RunDockerDevContainer( mountPath = strings.Replace(mountPath, ",consistency='consistent'", "", 1) } - // TODO somehow store DisableSELinuxFlag in options? - if ok, err := helper.SELinuxEnabled(ctx); ok && err == nil { - mountPath = fmt.Sprintf("%s,z", mountPath) - } else if err != nil { - d.Log.Infof("Unable to check if docker is running with SELinux. Assuming it is not.") + if options.DisableSELinuxFlag { + if ok, err := helper.SELinuxEnabled(ctx); ok && err == nil { + mountPath = fmt.Sprintf("%s,z", mountPath) + } else if err != nil { + d.Log.Infof("Unable to check if docker is running with SELinux. Assuming it is not.") + } } args = append(args, "--mount", mountPath) diff --git a/pkg/driver/types.go b/pkg/driver/types.go index 83b58b089..2e1ac6530 100644 --- a/pkg/driver/types.go +++ b/pkg/driver/types.go @@ -80,4 +80,7 @@ type RunOptions struct { // Bind mounts are expected to get copied from local to remote once. Volume mounts are expected // to be persisted for the lifetime of the container. Mounts []*config.Mount `json:"mounts,omitempty"` + + // DisableSELinuxFlag indicates if SELinux flags should be disabled for the Workspace mount + DisableSELinuxFlag bool `json:"disableSELinuxFlag,omitempty"` } diff --git a/pkg/provider/workspace.go b/pkg/provider/workspace.go index baf445281..f8362ae5f 100644 --- a/pkg/provider/workspace.go +++ b/pkg/provider/workspace.go @@ -222,6 +222,7 @@ type CLIOptions struct { GitSSHSigningKey string `json:"gitSshSigningKey,omitempty"` SSHAuthSockID string `json:"sshAuthSockID,omitempty"` // ID to use when looking for SSH_AUTH_SOCK, defaults to a new random ID if not set (only used for browser IDEs) StrictHostKeyChecking bool `json:"strictHostKeyChecking,omitempty"` + DisableSELinuxFlag bool `json:"disableSELinuxFlag,omitempty"` // build options Repository string `json:"repository,omitempty"`