From 235bf6c96a6d1a22adae60f0206f47d3170a1d69 Mon Sep 17 00:00:00 2001 From: Andrea Donetti Date: Mon, 27 Jul 2026 11:19:29 +0200 Subject: [PATCH 1/2] fix: make local Supabase build-from-source work on Alpine bases (#60) Compile the extension in a dedicated glibc builder stage (official postgres: image with PGDG headers, the same toolchain that builds the release artifacts) instead of installing an apt toolchain into the Supabase base, and resolve pg_config in the runtime stage by probing the Nix profile paths instead of hardcoding the Ubuntu-only location. The runtime stage no longer needs a compiler or package manager, so the Ubuntu/Alpine userland difference stops mattering; both families run a Nix-built, glibc-linked PostgreSQL, so the same .so serves both. postgres-supabase-build derives the builder's PG major version from the resolved base image tag, so auto-detection from a running Supabase CLI stack picks matching headers for PG15 vs PG17. Verified: CREATE EXTENSION cloudsync + cloudsync_version() on Alpine 17.6.1.151 and Ubuntu 17.6.1.071 / 15.8.1.135. Closes #60 Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 1 + docker/Makefile.postgresql | 6 +- docker/postgresql/Dockerfile.supabase | 96 ++++++++++++++++----------- 3 files changed, 63 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d260b9..b99bfdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed +- **The local build-from-source path (`make postgres-supabase-build`, `docker/postgresql/Dockerfile.supabase`) now works with the Alpine-userland Supabase bases** as well as the Ubuntu ones. The extension is compiled in a dedicated glibc builder stage (official `postgres:` image with PGDG headers, the same toolchain that produces the release artifacts) whose PostgreSQL major version is derived from the base image tag, and `pg_config` is resolved by probing the Nix profile paths instead of a hardcoded Ubuntu-only path. The runtime stage no longer needs a compiler or package manager, so the base userland is irrelevant. - **The `sqlitecloud/sqlite-sync-supabase:15` image now builds on Supabase base `15.8.1.135`** (previously `15.8.1.085`), which moves it from Ubuntu 20.04 to 24.04. Ubuntu 24.04 allocates system UIDs differently, so the `postgres` user changes from `105:106` to `101:102` and an **existing** data directory becomes unreadable: the container fails with `cat: /etc/postgresql-custom/pgsodium_root.key: Permission denied` followed by `FATAL: invalid secret key`. Existing deployments need a one-time `chown -R 101:102` on the data directory and the `supabase_db-config` volume before starting the new image — see [Self-Hosted Supabase](docs/postgresql/quickstarts/supabase-self-hosted.md) for the procedure. New deployments are unaffected, and the CloudSync extension itself is unchanged. ## [1.1.2] - 2026-07-13 diff --git a/docker/Makefile.postgresql b/docker/Makefile.postgresql index f5303bd..8e699a3 100644 --- a/docker/Makefile.postgresql +++ b/docker/Makefile.postgresql @@ -364,10 +364,12 @@ postgres-supabase-build: rm -f "$$tmp_dockerfile"; \ exit 1; \ fi; \ - echo "Using base image: $$supabase_cli_image"; \ + pg_major="$${supabase_cli_image##*:}"; pg_major="$${pg_major%%.*}"; \ + case "$$pg_major" in ''|*[!0-9]*) pg_major=17;; esac; \ + echo "Using base image: $$supabase_cli_image (PostgreSQL major $$pg_major)"; \ echo "Pulling fresh base image to avoid layer accumulation..."; \ docker pull "$$supabase_cli_image" 2>/dev/null || true; \ - docker build --build-arg SUPABASE_POSTGRES_TAG="$(SUPABASE_POSTGRES_TAG)" --build-arg CLOUDSYNC_VERSION="$(CLOUDSYNC_VERSION_FULL)" -f "$$tmp_dockerfile" -t "$$supabase_cli_image" .; \ + docker build --build-arg SUPABASE_POSTGRES_TAG="$(SUPABASE_POSTGRES_TAG)" --build-arg PG_MAJOR="$$pg_major" --build-arg CLOUDSYNC_VERSION="$(CLOUDSYNC_VERSION_FULL)" -f "$$tmp_dockerfile" -t "$$supabase_cli_image" .; \ rm -f "$$tmp_dockerfile"; \ echo "Build complete: $$supabase_cli_image" diff --git a/docker/postgresql/Dockerfile.supabase b/docker/postgresql/Dockerfile.supabase index 983a74a..d132aac 100644 --- a/docker/postgresql/Dockerfile.supabase +++ b/docker/postgresql/Dockerfile.supabase @@ -1,13 +1,27 @@ -# Build stage for CloudSync extension (match Supabase runtime) +# Supabase PostgreSQL with CloudSync (sqlite-sync) built from source +# +# Works with both Supabase base image families: +# - Ubuntu/glibc images (e.g. PG15 15.8.1.135, older PG17 17.6.1.071) +# - Alpine-userland images (e.g. PG17 17.6.1.084+); still a glibc Nix postgres +# Both families run a Nix-built, glibc-linked PostgreSQL, so the extension is +# compiled in a glibc builder stage (official postgres image + PGDG headers, +# the same toolchain that produces the release artifacts) and the identical +# .so is installed on either base. The runtime stage needs no compiler, so +# its userland (apt vs apk) never matters. +# +# PG_MAJOR must match the major version of SUPABASE_POSTGRES_TAG; the +# postgres-supabase-build Makefile target derives it automatically. +ARG PG_MAJOR=17 ARG SUPABASE_POSTGRES_TAG=17.6.1.071 -FROM public.ecr.aws/supabase/postgres:${SUPABASE_POSTGRES_TAG} AS cloudsync-builder -# Install build dependencies -RUN apt-get update && apt-get install -y \ +# Build stage for CloudSync extension (glibc toolchain, matching PG headers) +FROM postgres:${PG_MAJOR} AS cloudsync-builder +ARG PG_MAJOR + +# Install build dependencies (PGDG apt repo is preconfigured in this image) +RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ - ca-certificates \ - git \ - make \ + postgresql-server-dev-${PG_MAJOR} \ && rm -rf /var/lib/apt/lists/* # Create directory for extension source @@ -19,15 +33,10 @@ COPY modules/ ./modules/ COPY docker/ ./docker/ COPY Makefile . -# Build the CloudSync extension using Supabase's pg_config -ENV CLOUDSYNC_PG_CONFIG=/root/.nix-profile/bin/pg_config -RUN if [ ! -x "$CLOUDSYNC_PG_CONFIG" ]; then \ - echo "Error: pg_config not found at $CLOUDSYNC_PG_CONFIG."; \ - exit 1; \ - fi; \ - make postgres-build PG_CONFIG="$CLOUDSYNC_PG_CONFIG" +# Build the CloudSync extension against the PGDG headers +RUN make postgres-build PG_CONFIG=/usr/lib/postgresql/${PG_MAJOR}/bin/pg_config -# Collect build artifacts (avoid installing into the Nix store) +# Collect build artifacts RUN mkdir -p /tmp/cloudsync-artifacts/lib /tmp/cloudsync-artifacts/extension && \ cp /tmp/cloudsync/cloudsync.so /tmp/cloudsync-artifacts/lib/ && \ cp /tmp/cloudsync/src/postgresql/cloudsync--*.sql /tmp/cloudsync-artifacts/extension/ && \ @@ -38,52 +47,63 @@ RUN mkdir -p /tmp/cloudsync-artifacts/lib /tmp/cloudsync-artifacts/extension && fi # Runtime image based on Supabase Postgres -ARG SUPABASE_POSTGRES_TAG=17.6.1.071 FROM public.ecr.aws/supabase/postgres:${SUPABASE_POSTGRES_TAG} # Extension version (derived from src/cloudsync.h by the Makefile and passed in # as a build arg); used only for the image label. ARG CLOUDSYNC_VERSION=unknown -# Match builder pg_config path -ENV CLOUDSYNC_PG_CONFIG=/root/.nix-profile/bin/pg_config +# pg_config is resolved dynamically at build time (its path differs between the +# Ubuntu and Alpine Supabase bases). Pass --build-arg CLOUDSYNC_PG_CONFIG= +# to override. Kept an ARG so it does not leak into the built image. +ARG CLOUDSYNC_PG_CONFIG="" # Install CloudSync extension artifacts COPY --from=cloudsync-builder /tmp/cloudsync-artifacts/ /tmp/cloudsync-artifacts/ -RUN if [ ! -x "$CLOUDSYNC_PG_CONFIG" ]; then \ - echo "Error: pg_config not found at $CLOUDSYNC_PG_CONFIG."; \ - exit 1; \ +RUN set -eu; \ + # Resolve pg_config: the Nix profiles the Supabase bases ship first, PATH last + PG_CONFIG="${CLOUDSYNC_PG_CONFIG:-}"; \ + if [ -z "$PG_CONFIG" ]; then \ + for c in /root/.nix-profile/bin/pg_config /nix/var/nix/profiles/default/bin/pg_config "$(command -v pg_config || true)"; do \ + if [ -x "$c" ]; then PG_CONFIG="$c"; break; fi; \ + done; \ fi; \ - PKGLIBDIR="`$CLOUDSYNC_PG_CONFIG --pkglibdir`"; \ + if [ ! -x "$PG_CONFIG" ]; then echo "Error: pg_config not found${PG_CONFIG:+ at $PG_CONFIG}"; exit 1; fi; \ + PKGLIBDIR="$(${PG_CONFIG} --pkglibdir)"; \ # Supabase wraps postgres and overrides libdir via NIX_PGLIBDIR. - NIX_PGLIBDIR="`grep -E \"^export NIX_PGLIBDIR\" /usr/bin/postgres | sed -E \"s/.*'([^']+)'.*/\\1/\"`"; \ + NIX_PGLIBDIR="$(grep -E '^export NIX_PGLIBDIR' /usr/bin/postgres | sed -E "s/.*'([^']+)'.*/\1/" || true)"; \ if [ -n "$NIX_PGLIBDIR" ]; then PKGLIBDIR="$NIX_PGLIBDIR"; fi; \ - SHAREDIR_PGCONFIG="`$CLOUDSYNC_PG_CONFIG --sharedir`"; \ + SHAREDIR_PGCONFIG="$(${PG_CONFIG} --sharedir)"; \ SHAREDIR_STD="/usr/share/postgresql"; \ - install -d "$PKGLIBDIR" "$SHAREDIR_PGCONFIG/extension" && \ - install -m 755 /tmp/cloudsync-artifacts/lib/cloudsync.so "$PKGLIBDIR/" && \ + install -d "$PKGLIBDIR" "$SHAREDIR_PGCONFIG/extension"; \ + install -m 755 /tmp/cloudsync-artifacts/lib/cloudsync.so "$PKGLIBDIR/"; \ install -m 644 /tmp/cloudsync-artifacts/extension/cloudsync* "$SHAREDIR_PGCONFIG/extension/"; \ - if [ "$SHAREDIR_STD" != "$SHAREDIR_PGCONFIG" ]; then \ - install -d "$SHAREDIR_STD/extension" && \ + if [ "$SHAREDIR_STD" != "$SHAREDIR_PGCONFIG" ] && [ -d "$SHAREDIR_STD" ]; then \ + install -d "$SHAREDIR_STD/extension"; \ install -m 644 /tmp/cloudsync-artifacts/extension/cloudsync* "$SHAREDIR_STD/extension/"; \ - fi + fi; \ + rm -rf /tmp/cloudsync-artifacts # Verify installation -RUN if [ ! -x "$CLOUDSYNC_PG_CONFIG" ]; then \ - echo "Error: pg_config not found at $CLOUDSYNC_PG_CONFIG."; \ - exit 1; \ +RUN set -eu; \ + PG_CONFIG="${CLOUDSYNC_PG_CONFIG:-}"; \ + if [ -z "$PG_CONFIG" ]; then \ + for c in /root/.nix-profile/bin/pg_config /nix/var/nix/profiles/default/bin/pg_config "$(command -v pg_config || true)"; do \ + if [ -x "$c" ]; then PG_CONFIG="$c"; break; fi; \ + done; \ fi; \ - NIX_PGLIBDIR="`grep -E \"^export NIX_PGLIBDIR\" /usr/bin/postgres | sed -E \"s/.*'([^']+)'.*/\\1/\"`"; \ - echo "Verifying CloudSync extension installation..." && \ + if [ ! -x "$PG_CONFIG" ]; then echo "Error: pg_config not found${PG_CONFIG:+ at $PG_CONFIG}"; exit 1; fi; \ + NIX_PGLIBDIR="$(grep -E '^export NIX_PGLIBDIR' /usr/bin/postgres | sed -E "s/.*'([^']+)'.*/\1/" || true)"; \ + echo "Verifying CloudSync extension installation..."; \ if [ -n "$NIX_PGLIBDIR" ]; then \ ls -la "$NIX_PGLIBDIR/cloudsync.so"; \ else \ - ls -la "`$CLOUDSYNC_PG_CONFIG --pkglibdir`/cloudsync.so"; \ - fi && \ - ls -la "`$CLOUDSYNC_PG_CONFIG --sharedir`/extension/cloudsync"* && \ + ls -la "$(${PG_CONFIG} --pkglibdir)/cloudsync.so"; \ + fi; \ + ls -la "$(${PG_CONFIG} --sharedir)/extension/cloudsync"*; \ if [ -d "/usr/share/postgresql/extension" ]; then \ ls -la /usr/share/postgresql/extension/cloudsync*; \ - fi && \ + fi; \ echo "CloudSync extension installed successfully" # Expose PostgreSQL port From 0ad6c462a45ffd8aecbc0fd7c485b0c7e10fa6f7 Mon Sep 17 00:00:00 2001 From: Andrea Donetti Date: Mon, 27 Jul 2026 11:30:42 +0200 Subject: [PATCH 2/2] fix: align .PHONY and postgres-help with actual smoke-test target names The targets are postgres-supabase-run-test / postgres-docker-run-test, but .PHONY and the help text advertised *-run-smoke-test, which does not exist. Co-Authored-By: Claude Fable 5 --- docker/Makefile.postgresql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/Makefile.postgresql b/docker/Makefile.postgresql index 8e699a3..c765d8d 100644 --- a/docker/Makefile.postgresql +++ b/docker/Makefile.postgresql @@ -108,8 +108,8 @@ PG_MIGRATION_SQLS = $(wildcard $(PG_MIGRATIONS_DIR)/$(EXTENSION)--*--*.sql) postgres-docker-build postgres-docker-build-asan postgres-docker-run postgres-docker-run-asan postgres-docker-stop postgres-docker-rebuild \ postgres-docker-debug-build postgres-docker-debug-run postgres-docker-debug-rebuild \ postgres-docker-shell postgres-dev-rebuild postgres-help unittest-pg \ - postgres-supabase-build postgres-supabase-rebuild postgres-supabase-run-smoke-test \ - postgres-docker-run-smoke-test + postgres-supabase-build postgres-supabase-rebuild postgres-supabase-run-test \ + postgres-docker-run-test # Verify that a cloudsync----.sql upgrade script exists for the # current CLOUDSYNC_VERSION in src/cloudsync.h. Release-blocking: a missing @@ -436,8 +436,8 @@ postgres-help: @echo " postgres-docker-shell - Open bash shell in running container" @echo " postgres-supabase-build - Build CloudSync into Supabase CLI postgres image" @echo " postgres-supabase-rebuild - Build CloudSync image and restart Supabase CLI stack" - @echo " postgres-supabase-run-smoke-test - Run smoke test against Supabase CLI database" - @echo " postgres-docker-run-smoke-test - Run smoke test against Docker database" + @echo " postgres-supabase-run-test - Run smoke test against Supabase CLI database" + @echo " postgres-docker-run-test - Run smoke test against Docker database" @echo "" @echo "Development:" @echo " postgres-dev-rebuild - Rebuild extension in running container (fast)"