Skip to content
Merged
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
15 changes: 15 additions & 0 deletions .github/workflows/ci-kilobase-runner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,20 @@ jobs:
echo "=== Test basic SQL ==="
docker exec pg-test-17 psql -U supabase_admin -h localhost -d postgres -c "CREATE TABLE test_health (id serial PRIMARY KEY, data text); INSERT INTO test_health (data) VALUES ('ok'); SELECT * FROM test_health; DROP TABLE test_health;"

- name: Test KBVE extensions
run: |
echo "=== Test pgvector ==="
docker exec pg-test-17 psql -U supabase_admin -h localhost -d postgres -c "CREATE EXTENSION IF NOT EXISTS vector; SELECT extname, extversion FROM pg_extension WHERE extname = 'vector';"

echo "=== Test kilobase ==="
docker exec pg-test-17 psql -U supabase_admin -h localhost -d postgres -c "CREATE EXTENSION kilobase; SELECT extname, extversion FROM pg_extension WHERE extname = 'kilobase';"

echo "=== Test vchord ==="
docker exec pg-test-17 psql -U supabase_admin -h localhost -d postgres -c "CREATE EXTENSION vchord; SELECT extname, extversion FROM pg_extension WHERE extname = 'vchord';"

echo "=== Verify all loaded ==="
docker exec pg-test-17 psql -U supabase_admin -h localhost -d postgres -c "SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'kilobase', 'vchord') ORDER BY extname;"

- name: Cleanup test container
if: always()
run: docker rm -f pg-test-17 || true
Expand Down Expand Up @@ -201,6 +215,7 @@ jobs:

### Fork Customizations
- kilobase (pgrx 0.16.1 extension)
- vchord / VectorChord (pgrx 0.17.0 — scalable vector search)
- pg_failover_slots (logical replication slot failover)
- All standard Supabase PostgreSQL extensions

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ common-nix.vars.pkr.hcl
nixos.qcow2
.lsp
.clj-kondo
tools/pgrx-hash/output/result.json
5 changes: 5 additions & 0 deletions nix/cargo-pgrx/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,10 @@ in
hash = "sha256-3TsNpEqNm3Uol5XPW1i0XEbP2fF2+RKB2d7lO6BDnvQ=";
cargoHash = "sha256-LZUXhjMxkBs3O5feH4X5NQC7Qk4Ja6M5+sAYaSCikrY=";
};
cargo-pgrx_0_17_0 = mkCargoPgrx {
version = "0.17.0";
hash = "sha256-Ld7m7ggxlf8FufpeiAE9qcu49X0SgX6XXHS6KIewGyA=";
cargoHash = "sha256-hNj39YzJna8iZxnlrLz+uLduxaD+uvggQRM7ng3MN1k=";
};
inherit mkCargoPgrx;
}
8 changes: 8 additions & 0 deletions nix/cargo-pgrx/versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,13 @@
"cargoHash": "sha256-95DHq5GLnAqb3bbKwwaeBeKEmkfRh81ZTRaJ7L59DAg="
}
}
},
"0.17.0": {
"hash": "sha256-Ld7m7ggxlf8FufpeiAE9qcu49X0SgX6XXHS6KIewGyA=",
"rust": {
"1.90.0": {
"cargoHash": "sha256-hNj39YzJna8iZxnlrLz+uLduxaD+uvggQRM7ng3MN1k="
}
}
}
}
59 changes: 59 additions & 0 deletions nix/ext/vectorchord.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
lib,
stdenv,
callPackages,
postgresql,
rust-bin,
}:
let
pname = "vchord";
version = "1.1.0";
rustVersion = "1.90.0";
pgrxVersion = "0.17.0";

cargo = rust-bin.stable.${rustVersion}.default;
mkPgrxExtension = callPackages ../cargo-pgrx/mkPgrxExtension.nix {
inherit rustVersion pgrxVersion;
};

src = builtins.fetchGit {
url = "https://github.com/tensorchord/VectorChord.git";
rev = "c68a6aec9446899d0ab22662968053bd2820ddd4";
shallow = true;
};
in
mkPgrxExtension {
inherit
pname
version
postgresql
src
;

nativeBuildInputs = [ cargo ];
buildInputs = [ postgresql ];

cargoLock = {
lockFile = "${src}/Cargo.lock";
allowBuiltinFetchGit = true;
};

buildFeatures = [ "pg17" ];

CARGO = "${cargo}/bin/cargo";

env = lib.optionalAttrs stdenv.isDarwin {
POSTGRES_LIB = "${postgresql}/lib";
RUSTFLAGS = "-C link-arg=-undefined -C link-arg=dynamic_lookup";
};

doCheck = false;
auditable = false;

meta = with lib; {
description = "Scalable, fast, and disk-friendly vector search for Postgres";
homepage = "https://github.com/tensorchord/VectorChord";
platforms = postgresql.meta.platforms;
license = licenses.agpl3Plus;
};
}
1 change: 1 addition & 0 deletions nix/packages/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
cargo-pgrx_0_12_6
cargo-pgrx_0_12_9
cargo-pgrx_0_14_3
cargo-pgrx_0_17_0
;
}
// lib.optionalAttrs pkgs.stdenv.isDarwin {
Expand Down
2 changes: 1 addition & 1 deletion nix/packages/postgres.nix
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
) ourExtensions;

orioledbExtensions = orioleFilteredExtensions ++ [ ../ext/orioledb.nix ];
dbExtensions17 = orioleFilteredExtensions ++ [ ../ext/kilobase.nix ];
dbExtensions17 = orioleFilteredExtensions ++ [ ../ext/kilobase.nix ../ext/vectorchord.nix ];

# CLI extensions - minimal set for Supabase CLI with migration support
cliExtensions = [
Expand Down
13 changes: 13 additions & 0 deletions tools/pgrx-hash/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM --platform=linux/amd64 nixos/nix:latest

# Disable sandbox (required for QEMU-emulated builds on ARM hosts)
# and enable flakes
RUN echo "sandbox = false" >> /etc/nix/nix.conf \
&& echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf \
&& echo "filter-syscalls = false" >> /etc/nix/nix.conf

WORKDIR /work
COPY bootstrap.sh /work/bootstrap.sh
RUN chmod +x /work/bootstrap.sh

ENTRYPOINT ["/work/bootstrap.sh"]
50 changes: 50 additions & 0 deletions tools/pgrx-hash/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# pgrx Hash Bootstrap Tool

Computes Nix SRI hashes for new `cargo-pgrx` versions. Uses Docker (`linux/amd64`) so ARM machines (Apple Silicon) produce correct x86_64 hashes.

## Usage

```bash
# From repo root:
./tools/pgrx-hash/run.sh <pgrx-version> <rust-version>

# Example: bootstrap pgrx 0.17.0 with Rust 1.90.0
./tools/pgrx-hash/run.sh 0.17.0 1.90.0
```

## What It Does

1. Builds a Docker container targeting `linux/amd64` (uses QEMU on ARM hosts)
2. Fetches `cargo-pgrx` crate from crates.io and computes the source SRI hash
3. Builds `cargo-pgrx` to compute the Cargo dependency hash (`cargoHash`)
4. Writes result to `tools/pgrx-hash/output/result.json` (cached locally)
5. Auto-merges into `nix/cargo-pgrx/versions.json` (requires `jq` on host)

## Output

Results are written to `tools/pgrx-hash/output/result.json`:

```json
{
"pgrxVersion": "0.17.0",
"rustVersion": "1.90.0",
"hash": "sha256-...",
"cargoHash": "sha256-..."
}
```

This file is gitignored and persists locally for reference.

## When to Use

Run this tool whenever a new pgrx version is needed for an extension:

- Adding a new extension that requires a newer pgrx (e.g., VectorChord needs 0.17.0)
- Upgrading an existing extension to a newer pgrx version
- Adding support for a new Rust version with an existing pgrx version

## Requirements

- Docker with buildx support (for `--platform linux/amd64`)
- On ARM hosts: QEMU user-static registered (usually automatic with Docker Desktop)
- `jq` on the host for auto-merging into versions.json (optional — results are also in output/)
103 changes: 103 additions & 0 deletions tools/pgrx-hash/bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env bash
set -euo pipefail

PGRX_VERSION="${1:?Usage: bootstrap.sh <pgrx-version> <rust-version>}"
RUST_VERSION="${2:?Usage: bootstrap.sh <pgrx-version> <rust-version>}"
OUTPUT_DIR="${3:-/output}"

echo "=== Bootstrapping pgrx ${PGRX_VERSION} with Rust ${RUST_VERSION} ==="
echo ""

# Step 1: Compute the crate source hash from crates.io
echo "--- Step 1: Fetching cargo-pgrx ${PGRX_VERSION} from crates.io ---"
CRATE_URL="https://static.crates.io/crates/cargo-pgrx/cargo-pgrx-${PGRX_VERSION}.crate"
STORE_PATH=$(nix-prefetch-url --unpack "${CRATE_URL}" 2>/dev/null)
CRATE_HASH=$(nix hash to-sri --type sha256 "${STORE_PATH}")
echo "Crate hash: ${CRATE_HASH}"
echo ""

# Step 2: Build cargo-pgrx in a minimal flake to extract the cargoHash
echo "--- Step 2: Computing cargoHash (this builds cargo-pgrx dependencies) ---"
echo "(This will intentionally fail once to reveal the correct hash)"
TMPDIR=$(mktemp -d)

cat > "${TMPDIR}/flake.nix" << EOF
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { nixpkgs, rust-overlay, ... }:
let
pkgs = import nixpkgs {
system = "x86_64-linux";
overlays = [ (import rust-overlay) ];
};
rustToolchain = pkgs.rust-bin.stable."${RUST_VERSION}".default;
rustPlatform = pkgs.makeRustPlatform {
cargo = rustToolchain;
rustc = rustToolchain;
};
in {
packages.x86_64-linux.default = rustPlatform.buildRustPackage rec {
pname = "cargo-pgrx";
version = "${PGRX_VERSION}";
src = pkgs.fetchCrate {
inherit pname version;
hash = "${CRATE_HASH}";
};
cargoHash = "";
nativeBuildInputs = [ pkgs.pkg-config ];
buildInputs = [ pkgs.openssl ];
doCheck = false;
auditable = false;
};
};
}
EOF

# The build will fail because cargoHash is empty, but it will print the correct hash
BUILD_OUTPUT=$(nix build "${TMPDIR}#default" -L 2>&1 || true)

# Extract the hash from the error output - try multiple patterns
CARGO_HASH=$(echo "${BUILD_OUTPUT}" | grep -oP 'got:\s+\K\S+' | head -1 || true)

if [ -z "${CARGO_HASH}" ]; then
CARGO_HASH=$(echo "${BUILD_OUTPUT}" | grep "got:" | head -1 | sed 's/.*got:[[:space:]]*//' | tr -d ' ' || true)
fi

rm -rf "${TMPDIR}"

if [ -z "${CARGO_HASH}" ]; then
echo "ERROR: Could not extract cargoHash from build output."
echo "Build output (last 40 lines):"
echo "${BUILD_OUTPUT}" | tail -40
exit 1
fi
echo "Cargo hash: ${CARGO_HASH}"
echo ""

# Step 3: Write result JSON to output directory
echo "--- Step 3: Writing result to ${OUTPUT_DIR}/result.json ---"
mkdir -p "${OUTPUT_DIR}"

cat > "${OUTPUT_DIR}/result.json" << JSON
{
"pgrxVersion": "${PGRX_VERSION}",
"rustVersion": "${RUST_VERSION}",
"hash": "${CRATE_HASH}",
"cargoHash": "${CARGO_HASH}"
}
JSON

echo ""
echo "=== Results ==="
echo "pgrx version: ${PGRX_VERSION}"
echo "rust version: ${RUST_VERSION}"
echo "crate hash: ${CRATE_HASH}"
echo "cargo hash: ${CARGO_HASH}"
echo ""
echo "Result written to ${OUTPUT_DIR}/result.json"
Empty file added tools/pgrx-hash/output/.gitkeep
Empty file.
68 changes: 68 additions & 0 deletions tools/pgrx-hash/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
OUTPUT_DIR="${SCRIPT_DIR}/output"

PGRX_VERSION="${1:?Usage: run.sh <pgrx-version> <rust-version>}"
RUST_VERSION="${2:?Usage: run.sh <pgrx-version> <rust-version>}"
VERSIONS_JSON="${REPO_ROOT}/nix/cargo-pgrx/versions.json"

echo "=== pgrx Hash Bootstrap Tool ==="
echo "pgrx: ${PGRX_VERSION}, Rust: ${RUST_VERSION}"
echo "Target: linux/amd64 (via Docker)"
echo ""

# Ensure output directory exists
mkdir -p "${OUTPUT_DIR}"

echo "Building hash bootstrap container (linux/amd64)..."
docker build --platform linux/amd64 -t pgrx-hash-bootstrap "${SCRIPT_DIR}"

echo ""
echo "Running hash bootstrap..."
# Mount local output dir for the container to write results into
docker run --rm --platform linux/amd64 \
--privileged \
--security-opt seccomp=unconfined \
-v "${OUTPUT_DIR}:/output" \
pgrx-hash-bootstrap \
"${PGRX_VERSION}" "${RUST_VERSION}" "/output"

echo ""

# Read the result and merge into versions.json
RESULT_FILE="${OUTPUT_DIR}/result.json"
if [ ! -f "${RESULT_FILE}" ]; then
echo "ERROR: No result.json found in ${OUTPUT_DIR}"
echo "The container may have failed. Check output above."
exit 1
fi

echo "=== Result from container ==="
cat "${RESULT_FILE}"
echo ""

# Merge into versions.json if jq is available
if command -v jq &>/dev/null; then
CRATE_HASH=$(jq -r '.hash' "${RESULT_FILE}")
CARGO_HASH=$(jq -r '.cargoHash' "${RESULT_FILE}")

echo "--- Updating ${VERSIONS_JSON} ---"
jq --arg pv "${PGRX_VERSION}" \
--arg ch "${CRATE_HASH}" \
--arg rv "${RUST_VERSION}" \
--arg crh "${CARGO_HASH}" \
'.[$pv] = { hash: $ch, rust: { ($rv): { cargoHash: $crh } } }' \
"${VERSIONS_JSON}" > "${VERSIONS_JSON}.tmp" \
&& mv "${VERSIONS_JSON}.tmp" "${VERSIONS_JSON}"

echo "versions.json updated successfully!"
else
echo "WARNING: jq not found on host. Install jq to auto-merge, or copy"
echo "values from ${RESULT_FILE} into ${VERSIONS_JSON} manually."
fi

echo ""
echo "Done! Result cached in ${RESULT_FILE}"