diff --git a/docker-compose.debug.yaml b/docker-compose.debug.yaml index a69fae0..99b86a9 100644 --- a/docker-compose.debug.yaml +++ b/docker-compose.debug.yaml @@ -13,6 +13,14 @@ services: dockerfile: Dockerfile.debug environment: - DEV_MODE=true + - DCNTRLIZED_DEV=true + - GITEA_URL=${GITEA_URL:-http://192.168.122.184:3000} + - GITEA_REGISTRY_RO_TOKEN=${GITEA_REGISTRY_RO_TOKEN} + - GITEA_RW_PACKAGE_TOKEN=${GITEA_RW_PACKAGE_TOKEN} + - GITEA_ORG=${GITEA_ORG:-Dcntrlized} + - GITEA_USER=${GITEA_USER:-admin} + - GIT_TOKEN=${GIT_TOKEN} + - REGISTRY_USER=${REGISTRY_USER:-admin} networks: dcntrlized_net: diff --git a/docker-compose.yaml b/docker-compose.yaml index 06c52b9..5520d92 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -18,8 +18,11 @@ services: - GITEA_REGISTRY_RO_TOKEN=${GITEA_REGISTRY_RO_TOKEN} - GITEA_RW_PACKAGE_TOKEN=${GITEA_RW_PACKAGE_TOKEN} - GITEA_ORG=${GITEA_ORG:-Dcntrlized} - - GITEA_USER=${GITEA_USER:-Admin} + - GITEA_USER=${GITEA_USER:-admin} + - GITEA_URL=${GITEA_URL:-http://192.168.122.184:3000} + - DCNTRLIZED_DEV=${DCNTRLIZED_DEV:-true} - GIT_TOKEN=${GIT_TOKEN} + - REGISTRY_USER=${REGISTRY_USER:-admin} networks: dcntrlized_net: diff --git a/spec.yaml b/spec.yaml index d5634de..f27f211 100644 --- a/spec.yaml +++ b/spec.yaml @@ -41,7 +41,7 @@ components: example: "0.0.1" image: type: string - example: "git.dcntrlized.org/Dcntrlized/keepnote/keepnote:0.0.1" + example: "192.168.122.184:3000/dcntrlized/keepnote:dev" digest: type: string title: diff --git a/src/frontend/PRODUCT.md b/src/frontend/PRODUCT.md index f0f8705..32841b9 100644 --- a/src/frontend/PRODUCT.md +++ b/src/frontend/PRODUCT.md @@ -25,7 +25,9 @@ The mechanism is a Git-backed, decentralized service registry: services are publ - Live state flows over WebSocket (`ws://127.0.0.1:8080/api/ws`); the catalog is fetched once from `/api/registry`. - Real-time statuses come from Docker (running, exited, stopped, created, restarting) plus UI states (installed, uninstalled). - Service metadata (title, vendor, author, description, source, licenses, revision) comes from OCI annotations published with each image. -- Upstream registry is git.dcntrlized.org (Gitea), org `Dcntrlized`. +- Upstream registry defaults to git.dcntrlized.org (Gitea), org `Dcntrlized`; + in dev (`DCNTRLIZED_DEV=true`) it targets `GITEA_URL` (the dev VM + `192.168.122.184:3000`). - Maestro itself runs as a container (image `maestro`); its own container is hidden from the list. - Update detection compares the installed version against the registry latest via semver; versions are normalized to `X.Y.Z`. diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts index 71b90e0..f5bf3c1 100644 --- a/src/frontend/vite.config.ts +++ b/src/frontend/vite.config.ts @@ -21,7 +21,7 @@ export default defineConfig(({ command }): UserConfig => { ? { '/api': 'http://127.0.0.1:8080', '/gitea-api': { - target: 'https://git.dcntrlized.org', // Your Gitea base URL + target: process.env.GITEA_URL || 'https://git.dcntrlized.org', // Gitea base URL (override with GITEA_URL in dev) changeOrigin: true, rewrite: (path) => path.replace(/^\/gitea-api/, ''), }, diff --git a/src/handlers/registry/registry.go b/src/handlers/registry/registry.go index db75da3..f0ea56f 100644 --- a/src/handlers/registry/registry.go +++ b/src/handlers/registry/registry.go @@ -35,7 +35,7 @@ import ( func GetRegistry(w http.ResponseWriter, r *http.Request) { // 1. Query Gitea REST API using the exact Org name - apiURL := fmt.Sprintf("https://git.dcntrlized.org/api/v1/packages/%s?type=container", os.Getenv("GITEA_ORG")) + apiURL := fmt.Sprintf("%s/api/v1/packages/%s?type=container", giteaBaseURL(), os.Getenv("GITEA_ORG")) req, err := http.NewRequestWithContext(r.Context(), http.MethodGet, apiURL, nil) if err != nil { @@ -150,7 +150,7 @@ func GetRegistry(w http.ResponseWriter, r *http.Request) { // 4. Fetch OCI metadata only for the highest version of each package for _, pkg := range latestPackages { pkgNameLower := strings.ToLower(pkg.Name) - imageRef := fmt.Sprintf("git.dcntrlized.org/%s/%s:%s", ociOrg, pkgNameLower, pkg.Version) + imageRef := fmt.Sprintf("%s/%s/%s:%s", registryHost(), ociOrg, pkgNameLower, pkg.Version) // The Gitea package API does not link org-level container packages to a // repository, so the repository URL is resolved from the image's OCI @@ -162,7 +162,11 @@ func GetRegistry(w http.ResponseWriter, r *http.Request) { CreatedAt: pkg.CreatedAt, } - ref, err := name.ParseReference(imageRef) + var refOpts []name.Option + if isInsecureRegistry() { + refOpts = append(refOpts, name.Insecure) + } + ref, err := name.ParseReference(imageRef, refOpts...) if err != nil { logger.Error("Failed to parse image reference %s: %v", imageRef, err) registryItems = append(registryItems, item) @@ -284,11 +288,48 @@ func GetRegistry(w http.ResponseWriter, r *http.Request) { } // repoURLFromImageRef derives the repository browse URL from a container image -// reference of the form host/org/repo:tag (https://host/org/repo). +// reference of the form host/org/repo:tag (scheme://host/org/repo), using the +// scheme of the configured Gitea base URL. func repoURLFromImageRef(imageRef string) string { ref, err := name.ParseReference(imageRef) if err != nil { return "" } - return "https://" + ref.Context().RegistryStr() + "/" + ref.Context().RepositoryStr() + return giteaScheme() + "://" + ref.Context().RegistryStr() + "/" + ref.Context().RepositoryStr() +} + +// giteaBaseURL returns the Gitea instance base URL (scheme://host[:port]). +// Production defaults to git.dcntrlized.org; dev mode (DCNTRLIZED_DEV=true) +// overrides it with GITEA_URL when set. +func giteaBaseURL() string { + if os.Getenv("DCNTRLIZED_DEV") == "true" { + if u := strings.TrimRight(os.Getenv("GITEA_URL"), "/"); u != "" { + return u + } + } + return "https://git.dcntrlized.org" +} + +// registryHost strips the scheme from the Gitea base URL, returning just the +// host[:port] used in container image references. +func registryHost() string { + base := giteaBaseURL() + if i := strings.Index(base, "://"); i >= 0 { + return base[i+3:] + } + return base +} + +// isInsecureRegistry reports whether the Gitea registry is served over plain +// HTTP, in which case image references must be parsed with name.Insecure. +func isInsecureRegistry() bool { + return strings.HasPrefix(giteaBaseURL(), "http://") +} + +// giteaScheme returns the scheme (http/https) of the configured Gitea base URL. +func giteaScheme() string { + if i := strings.Index(giteaBaseURL(), "://"); i >= 0 { + return giteaBaseURL()[:i] + } + return "https" }