diff --git a/tools/thothctl/internal/pi/state.go b/tools/thothctl/internal/pi/state.go index a6543df1..52549700 100644 --- a/tools/thothctl/internal/pi/state.go +++ b/tools/thothctl/internal/pi/state.go @@ -136,6 +136,13 @@ func writeFileDurably(path, prefix string, contents []byte) error { } func mountSourceHash(source string) string { + source = filepath.Clean(source) + for _, dockerDesktopPrefix := range []string{"/host_mnt/private/var/", "/host_mnt/Users/"} { + if strings.HasPrefix(source, dockerDesktopPrefix) { + source = strings.TrimPrefix(source, "/host_mnt") + break + } + } sum := sha256.Sum256([]byte(source)) return fmt.Sprintf("%x", sum[:]) } diff --git a/tools/thothctl/internal/pi/update_test.go b/tools/thothctl/internal/pi/update_test.go index 40a68f68..dcd04e64 100644 --- a/tools/thothctl/internal/pi/update_test.go +++ b/tools/thothctl/internal/pi/update_test.go @@ -802,6 +802,25 @@ func TestRunningImageCapturesServerBindAndNamedMountIdentity(t *testing.T) { } } +func TestDockerDesktopBindAliasesKeepOnePersistenceIdentity(t *testing.T) { + for _, paths := range [][2]string{ + {"/private/var/folders/task/models.json", "/host_mnt/private/var/folders/task/models.json"}, + {"/Users/operator/thoth/models.json", "/host_mnt/Users/operator/thoth/models.json"}, + } { + left := Mount{Type: "bind", SourceSHA256: mountSourceHash(paths[0]), Destination: "/config/models.json"} + right := Mount{Type: "bind", SourceSHA256: mountSourceHash(paths[1]), Destination: "/config/models.json"} + if !sameMounts([]Mount{left}, []Mount{right}) { + t.Fatalf("Docker Desktop aliases were treated as different mounts: %q and %q", paths[0], paths[1]) + } + } + + left := Mount{Type: "bind", SourceSHA256: mountSourceHash("/srv/thoth/models.json"), Destination: "/config/models.json"} + right := Mount{Type: "bind", SourceSHA256: mountSourceHash("/host_mnt/srv/thoth/models.json"), Destination: "/config/models.json"} + if sameMounts([]Mount{left}, []Mount{right}) { + t.Fatal("an unknown /host_mnt path was collapsed into a distinct Linux bind source") + } +} + func TestCanonicalDigestReferenceRejectsCredentialsAndURLForms(t *testing.T) { valid := "registry.example.invalid/thothii-core@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" if got, err := canonicalDigestReference(valid); err != nil || got != valid {