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
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Table, TableBody, TableHead, TableHeader, TableRow } from "@podkit/tabl
import { useListConfigurationVariables } from "../../../data/configurations/configuration-queries";
import { LoadingState } from "@podkit/loading/LoadingState";
import { ConfigurationVariableItem } from "./ConfigurationVariableItem";
import { EnableDockerdAuthentication } from "./EnableDockerdAuthentication";

type Props = {
configuration: Configuration;
Expand All @@ -27,52 +28,55 @@ export const ConfigurationVariableList = ({ configuration }: Props) => {
}

return (
<ConfigurationSettingsField>
{showAddVariableModal && (
<AddVariableModal
configurationId={configuration.id}
onClose={() => {
setShowAddVariableModal(false);
}}
/>
)}
<div className="mb-2 flex">
<div className="flex-grow">
<Heading3>Environment variables</Heading3>
<Subheading>Manage repository-specific environment variables.</Subheading>
<>
<ConfigurationSettingsField>
{showAddVariableModal && (
<AddVariableModal
configurationId={configuration.id}
onClose={() => {
setShowAddVariableModal(false);
}}
/>
)}
<div className="mb-2 flex">
<div className="flex-grow">
<Heading3>Environment variables</Heading3>
<Subheading>Manage repository-specific environment variables.</Subheading>
</div>
</div>
</div>
{data.length === 0 ? (
<div className="bg-pk-surface-secondary rounded-xl w-full p-6 flex flex-col justify-center space-y-3">
<span className="font-semi-bold text-base">No environment variables are set</span>
<span className="text-sm text-pk-content-secondary">
All repository-specific environment variables will be visible in prebuilds and optionally in
workspaces for this repository.
</span>
</div>
) : (
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead className="w-48">Visibility</TableHead>
<TableHead className="w-16"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((variable) => (
<ConfigurationVariableItem
key={variable.id}
configurationId={configuration.id}
variable={variable}
/>
))}
</TableBody>
</Table>
)}
<Button className="mt-4" onClick={() => setShowAddVariableModal(true)}>
Add Variable
</Button>
</ConfigurationSettingsField>
{data.length === 0 ? (
<div className="bg-pk-surface-secondary rounded-xl w-full p-6 flex flex-col justify-center space-y-3">
<span className="font-semi-bold text-base">No environment variables are set</span>
<span className="text-sm text-pk-content-secondary">
All repository-specific environment variables will be visible in prebuilds and optionally in
workspaces for this repository.
</span>
</div>
) : (
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead className="w-48">Visibility</TableHead>
<TableHead className="w-16"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((variable) => (
<ConfigurationVariableItem
key={variable.id}
configurationId={configuration.id}
variable={variable}
/>
))}
</TableBody>
</Table>
)}
<Button className="mt-4" onClick={() => setShowAddVariableModal(true)}>
Add Variable
</Button>
</ConfigurationSettingsField>
<EnableDockerdAuthentication configuration={configuration} />
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* Copyright (c) 2025 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License.AGPL.txt in the project root for license information.
*/

import { SwitchInputField } from "@podkit/switch/Switch";
import { Heading3, Subheading } from "@podkit/typography/Headings";
import { FC, useCallback } from "react";
import { InputField } from "../../../components/forms/InputField";
import { useToast } from "../../../components/toasts/Toasts";
import { useId } from "../../../hooks/useId";
import { ConfigurationSettingsField } from "../ConfigurationSettingsField";
import { Configuration } from "@gitpod/public-api/lib/gitpod/v1/configuration_pb";
import { SquareArrowOutUpRight } from "lucide-react";
import { useConfiguration, useConfigurationMutation } from "../../../data/configurations/configuration-queries";
import Alert from "../../../components/Alert";

type Props = {
configuration: Configuration;
};
export const EnableDockerdAuthentication: FC<Props> = ({ configuration }) => {
const { data } = useConfiguration(configuration.id);
const configurationMutation = useConfigurationMutation();
const { toast } = useToast();

const updateEnableDockerdAuthentication = useCallback(
async (enable: boolean) => {
await configurationMutation.mutateAsync(
{
configurationId: configuration.id,
workspaceSettings: {
enableDockerdAuthentication: enable,
},
},
{
onError: (error) => {
toast(`Failed to update dockerd authentication: ${error.message}`);
},
},
);
},
[configurationMutation, configuration.id, toast],
);

const inputId = useId({ prefix: "enable-dockerd-authentication" });
const isEnabled = data?.workspaceSettings?.enableDockerdAuthentication;

return (
<ConfigurationSettingsField>
<Heading3 className="flex flex-row items-center gap-2">Docker registry authentication</Heading3>
<Subheading className="max-w-lg flex flex-col gap-2">
<span className="flex-1 text-left">
Enable authentication with Docker registries inside of workspaces based on the{" "}
<code>GITPOD_IMAGE_AUTH</code> environment variable.
</span>

<Alert type={"warning"} closable={false} showIcon={true} className="flex rounded p-2 mb-2 w-full">
By enabling this, credentials specified in <code>GITPOD_IMAGE_AUTH</code> will be visible inside all
workspaces on this project.
</Alert>
<a
className="gp-link flex flex-row items-center gap-1"
href="https://www.gitpod.io/docs/configure/repositories/environment-variables#docker-registry-authentication"
target="_blank"
rel="noreferrer"
>
Learn about using private Docker images with Gitpod
<SquareArrowOutUpRight size={12} />
</a>
</Subheading>
<InputField id={inputId}>
<SwitchInputField
id={inputId}
checked={isEnabled}
disabled={configurationMutation.isLoading}
onCheckedChange={updateEnableDockerdAuthentication}
label={isEnabled ? "Auto-login enabled" : "Auto-login disabled"}
/>
</InputField>
</ConfigurationSettingsField>
);
};
1 change: 1 addition & 0 deletions components/docker-up/BUILD.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ packages:
- go.mod
- go.sum
- "docker-up/**"
- "dockerd/**"
- dependencies.sh
deps:
- components/common-go:lib
Expand Down
108 changes: 10 additions & 98 deletions components/docker-up/docker-up/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ package main

import (
"archive/tar"
"bufio"
"compress/gzip"
"context"
"embed"
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -25,6 +23,7 @@ import (
"syscall"
"time"

"github.com/gitpod-io/gitpod/docker-up/dockerd"
"github.com/rootless-containers/rootlesskit/pkg/sigproxy"
sigproxysignal "github.com/rootless-containers/rootlesskit/pkg/sigproxy/signal"
"github.com/sirupsen/logrus"
Expand All @@ -45,6 +44,7 @@ var opts struct {
UserAccessibleSocket bool
Verbose bool
DontWrapNetNS bool
AutoLogin bool
}

//go:embed docker.tgz
Expand All @@ -58,6 +58,7 @@ var aptUpdated = false
const (
dockerSocketFN = "/var/run/docker.sock"
gitpodUserId = 33333
gitpodGroupId = 33333
containerIf = "eth0"
)

Expand All @@ -73,6 +74,7 @@ func main() {
pflag.BoolVar(&opts.AutoInstall, "auto-install", true, "auto-install prerequisites (docker)")
pflag.BoolVar(&opts.UserAccessibleSocket, "user-accessible-socket", true, "chmod the Docker socket to make it user accessible")
pflag.BoolVar(&opts.DontWrapNetNS, "dont-wrap-netns", os.Getenv("WORKSPACEKIT_WRAP_NETNS") == "true", "wrap the Docker daemon in a network namespace")
pflag.BoolVar(&opts.AutoLogin, "auto-login", false, "use content of GITPOD_IMAGE_AUTH to automatically login with the docker daemon")
pflag.Parse()

logger := logrus.New()
Expand Down Expand Up @@ -118,7 +120,8 @@ func runWithinNetns() (err error) {
)
}

userArgs, err := userArgs()
userArgsValue, _ := os.LookupEnv(DaemonArgs)
userArgs, err := dockerd.ParseUserArgs(log, userArgsValue)
if err != nil {
return xerrors.Errorf("cannot add user supplied docker args: %w", err)
}
Expand Down Expand Up @@ -192,98 +195,6 @@ func runWithinNetns() (err error) {
return nil
}

type ConvertUserArg func(arg, value string) ([]string, error)

var allowedDockerArgs = map[string]ConvertUserArg{
"remap-user": convertRemapUser,
}

func userArgs() ([]string, error) {
userArgs, exists := os.LookupEnv(DaemonArgs)
args := []string{}
if !exists {
return args, nil
}

var providedDockerArgs map[string]string
if err := json.Unmarshal([]byte(userArgs), &providedDockerArgs); err != nil {
return nil, xerrors.Errorf("unable to deserialize docker args: %w", err)
}

for userArg, userValue := range providedDockerArgs {
converter, exists := allowedDockerArgs[userArg]
if !exists {
continue
}

if converter != nil {
cargs, err := converter(userArg, userValue)
if err != nil {
return nil, xerrors.Errorf("could not convert %v - %v: %w", userArg, userValue, err)
}
args = append(args, cargs...)

} else {
args = append(args, "--"+userArg, userValue)
}
}

return args, nil
}

func convertRemapUser(arg, value string) ([]string, error) {
id, err := strconv.Atoi(value)
if err != nil {
return nil, err
}

for _, f := range []string{"/etc/subuid", "/etc/subgid"} {
err := adaptSubid(f, id)
if err != nil {
return nil, xerrors.Errorf("could not adapt subid files: %w", err)
}
}

return []string{"--userns-remap", "gitpod"}, nil
}

func adaptSubid(oldfile string, id int) error {
uid, err := os.Open(oldfile)
if err != nil {
return err
}

newfile, err := os.Create(oldfile + ".new")
if err != nil {
return err
}

mappingFmt := func(username string, id int, size int) string { return fmt.Sprintf("%s:%d:%d\n", username, id, size) }

if id != 0 {
newfile.WriteString(mappingFmt("gitpod", 1, id))
newfile.WriteString(mappingFmt("gitpod", gitpodUserId, 1))
} else {
newfile.WriteString(mappingFmt("gitpod", gitpodUserId, 1))
newfile.WriteString(mappingFmt("gitpod", 1, gitpodUserId-1))
newfile.WriteString(mappingFmt("gitpod", gitpodUserId+1, 32200)) // map rest of user ids in the user namespace
}

uidScanner := bufio.NewScanner(uid)
for uidScanner.Scan() {
l := uidScanner.Text()
if !strings.HasPrefix(l, "gitpod") {
newfile.WriteString(l + "\n")
}
}

if err = os.Rename(newfile.Name(), oldfile); err != nil {
return err
}

return nil
}

var prerequisites = map[string]func() error{
"dockerd": installDocker,
"docker-compose": installDockerCompose,
Expand Down Expand Up @@ -353,7 +264,8 @@ func installDocker() error {
}

switch hdr.Typeflag {
case tar.TypeReg, tar.TypeRegA:

case tar.TypeReg, tar.TypeRegA: //lint:ignore SA1019 backwards compatibility
file, err := os.OpenFile(dstpath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode)
if err != nil {
return xerrors.Errorf("unable to create file: %v", err)
Expand Down Expand Up @@ -480,12 +392,12 @@ func detectRuncVersion(output string) (major, minor int, err error) {

major, err = strconv.Atoi(n[0])
if err != nil {
return 0, 0, xerrors.Errorf("could not parse major %s: %w", n[0])
return 0, 0, xerrors.Errorf("could not parse major %s: %w", n[0], err)
}

minor, err = strconv.Atoi(n[1])
if err != nil {
return 0, 0, xerrors.Errorf("could not parse minor %s: %w", n[1])
return 0, 0, xerrors.Errorf("could not parse minor %s: %w", n[1], err)
}

return major, minor, nil
Expand Down
Loading
Loading