package main import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" ) func TestGatewayCreatesConstrainedBrowser(t *testing.T) { var created map[string]any docker := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { switch { case request.Method == http.MethodPost && request.URL.Path == "/v1.43/containers/create": if got := request.URL.Query().Get("name"); got != namePrefix+"account-a" { t.Fatalf("unexpected container name %q", got) } if err := json.NewDecoder(request.Body).Decode(&created); err != nil { t.Fatal(err) } response.WriteHeader(http.StatusCreated) _, _ = response.Write([]byte(`{"Id":"container-id"}`)) case request.Method == http.MethodPost && request.URL.Path == "/v1.43/containers/container-id/start": response.WriteHeader(http.StatusNoContent) default: t.Fatalf("unexpected Docker request %s %s", request.Method, request.URL.String()) } })) defer docker.Close() handler := newGateway(dockerClient{baseURL: docker.URL + "/v1.43", client: docker.Client()}, config{ image: "registry.example/browser:1.2.3", network: "creatorhub_browser", }) request := httptest.NewRequest(http.MethodPost, "/v1/browsers", strings.NewReader(`{"name":"account-a","seed":1000}`)) response := httptest.NewRecorder() handler.ServeHTTP(response, request) if response.Code != http.StatusCreated { t.Fatalf("expected 201, got %d: %s", response.Code, response.Body.String()) } if created["Image"] != "registry.example/browser:1.2.3" { t.Fatalf("gateway accepted an unexpected image: %#v", created["Image"]) } host := created["HostConfig"].(map[string]any) if host["NetworkMode"] != "creatorhub_browser" || host["ReadonlyRootfs"] != true { t.Fatalf("missing container isolation: %#v", host) } tmpfs := host["Tmpfs"].(map[string]any) if tmpfs["/tmp/.X11-unix"] == nil || tmpfs["/home/ubuntu"] == nil { t.Fatalf("missing writable runtime paths: %#v", tmpfs) } labels := created["Labels"].(map[string]any) if labels[managedLabel] != "true" || labels[idLabel] != "account-a" { t.Fatalf("missing ownership labels: %#v", labels) } } func TestGatewayRefusesUnmanagedContainer(t *testing.T) { deleted := false docker := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { switch request.Method { case http.MethodGet: _, _ = response.Write([]byte(`{"Config":{"Labels":{}}}`)) case http.MethodDelete: deleted = true response.WriteHeader(http.StatusNoContent) } })) defer docker.Close() handler := newGateway(dockerClient{baseURL: docker.URL, client: docker.Client()}, config{}) request := httptest.NewRequest(http.MethodDelete, "/v1/browsers/foreign", nil) response := httptest.NewRecorder() handler.ServeHTTP(response, request) if response.Code != http.StatusForbidden || deleted { t.Fatalf("expected unmanaged container to be rejected, status=%d deleted=%v", response.Code, deleted) } } func TestEnsureInternalNetwork(t *testing.T) { var created struct { Name string `json:"Name"` Driver string `json:"Driver"` Internal bool `json:"Internal"` Options map[string]string `json:"Options"` Labels map[string]string `json:"Labels"` } docker := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { switch request.Method { case http.MethodGet: response.WriteHeader(http.StatusNotFound) case http.MethodPost: if err := json.NewDecoder(request.Body).Decode(&created); err != nil { t.Fatal(err) } response.WriteHeader(http.StatusCreated) } })) defer docker.Close() client := dockerClient{baseURL: docker.URL, client: docker.Client()} if err := client.ensureInternalNetwork("creatorhub_browser"); err != nil { t.Fatal(err) } if created.Name != "creatorhub_browser" || created.Driver != "bridge" || !created.Internal || created.Options[bridgeICCOption] != "false" || len(created.Options) != 1 || created.Labels[managedLabel] != "true" || created.Labels[networkRoleLabel] != browserNetworkRole { t.Fatalf("network is not isolated: %#v", created) } } func TestEnsureInternalNetworkRejectsUnsafeExistingNetwork(t *testing.T) { valid := map[string]any{ "Name": "creatorhub_browser", "Driver": "bridge", "Internal": true, "Attachable": false, "Ingress": false, "Options": map[string]string{bridgeICCOption: "false"}, "Labels": map[string]string{ managedLabel: "true", networkRoleLabel: browserNetworkRole, }, } validDocker := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, _ *http.Request) { _ = json.NewEncoder(response).Encode(valid) })) defer validDocker.Close() client := dockerClient{baseURL: validDocker.URL, client: validDocker.Client()} if err := client.ensureInternalNetwork("creatorhub_browser"); err != nil { t.Fatalf("expected owned isolated network to be accepted: %v", err) } tests := map[string]func(map[string]any){ "wrong name": func(network map[string]any) { network["Name"] = "other" }, "wrong driver": func(network map[string]any) { network["Driver"] = "overlay" }, "external": func(network map[string]any) { network["Internal"] = false }, "attachable": func(network map[string]any) { network["Attachable"] = true }, "ingress": func(network map[string]any) { network["Ingress"] = true }, "missing ownership": func(network map[string]any) { network["Labels"] = map[string]string{networkRoleLabel: browserNetworkRole} }, "wrong role": func(network map[string]any) { network["Labels"] = map[string]string{managedLabel: "true", networkRoleLabel: "control"} }, "missing ICC": func(network map[string]any) { network["Options"] = map[string]string{} }, "enabled ICC": func(network map[string]any) { network["Options"] = map[string]string{bridgeICCOption: "true"} }, "extra option": func(network map[string]any) { network["Options"] = map[string]string{bridgeICCOption: "false", "unexpected": "value"} }, } for name, mutate := range tests { t.Run(name, func(t *testing.T) { network := make(map[string]any, len(valid)) for key, value := range valid { network[key] = value } mutate(network) docker := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, _ *http.Request) { _ = json.NewEncoder(response).Encode(network) })) defer docker.Close() client := dockerClient{baseURL: docker.URL, client: docker.Client()} if err := client.ensureInternalNetwork("creatorhub_browser"); err == nil { t.Fatal("expected unsafe existing network to be rejected") } }) } } func TestEnsureInternalNetworkRejectsControlNetwork(t *testing.T) { requested := false docker := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) { requested = true })) defer docker.Close() client := dockerClient{baseURL: docker.URL, client: docker.Client()} if err := client.ensureInternalNetwork(controlNetworkName); err == nil || requested { t.Fatalf("expected control network to be rejected before Docker request, requested=%v err=%v", requested, err) } }