Skip to content
Draft
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
10 changes: 8 additions & 2 deletions internal/worker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"regexp"
"strings"
"time"

Expand All @@ -22,6 +23,9 @@ import (

const dockerHubAuthConfigKey = "https://index.docker.io/v1/"

// invalidVolumeNameChars matches characters not allowed in Docker volume names.
var invalidVolumeNameChars = regexp.MustCompile(`[^a-zA-Z0-9_.-]`)

// DockerBackendConfig holds configuration specific to the Docker backend.
type DockerBackendConfig struct {
NoCleanup bool
Expand Down Expand Up @@ -514,8 +518,10 @@ func sanitizeVolumeName(imageName, digest string) string {
repoName = imageName
}

// Sanitize the repository name for use in volume name
baseName := strings.ReplaceAll(repoName, "/", "-")
// Sanitize the repository name for use in volume name. Docker volume names
// only allow [a-zA-Z0-9_.-], so registry hosts with ports (e.g.
// localhost:5000/warp-agent) must have their colons replaced too.
baseName := invalidVolumeNameChars.ReplaceAllString(repoName, "-")

// digest format is typically "sha256:abc123..."
parts := strings.Split(digest, ":")
Expand Down
46 changes: 46 additions & 0 deletions internal/worker/docker_volume_name_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package worker

import "testing"

func TestSanitizeVolumeName(t *testing.T) {
tests := []struct {
name string
imageName string
digest string
want string
}{
{
name: "docker hub image",
imageName: "warpdotdev/warp-agent:latest-dev",
digest: "sha256:cdd2970ebf33dea820d96c39246d0db275f1e33965e9b65381e778eb77a7a1af",
want: "warpdotdev-warp-agent-cdd2970ebf33",
},
{
name: "registry host with port",
imageName: "localhost:5000/warp-agent:pr120",
digest: "sha256:cdd2970ebf33dea820d96c39246d0db275f1e33965e9b65381e778eb77a7a1af",
want: "localhost-5000-warp-agent-cdd2970ebf33",
},
{
name: "registry host with port and nested repo",
imageName: "registry.example.com:8443/team/agent:v1",
digest: "sha256:abcdef0123456789",
want: "registry.example.com-8443-team-agent-abcdef012345",
},
{
name: "malformed digest falls back to base name plus digest",
imageName: "warpdotdev/warp-agent",
digest: "not-a-digest",
want: "warpdotdev-warp-agent-not-a-digest",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := sanitizeVolumeName(tt.imageName, tt.digest)
if got != tt.want {
t.Errorf("sanitizeVolumeName(%q, %q) = %q, want %q", tt.imageName, tt.digest, got, tt.want)
}
})
}
}
Loading