From 963c777ed7b0b2fd6fb675d84cb560581da4d122 Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Tue, 28 Jul 2026 15:03:36 +0000 Subject: [PATCH 1/5] feat: add `pgrouting` container image Add pgRouting extension container image for CloudNativePG targeting PostgreSQL 18 across Debian bookworm and trixie distributions. Signed-off-by: Oliver Falk --- pgrouting/Dockerfile | 81 ++++++++++++++++++++++ pgrouting/README.md | 80 +++++++++++++++++++++ pgrouting/metadata.hcl | 35 ++++++++++ pgrouting/test/chainsaw-test.yaml | 28 ++++++++ pgrouting/test/check-extension-assert.yaml | 6 ++ pgrouting/test/check-extension.yaml | 28 ++++++++ pgrouting/test/cluster-assert.yaml | 8 +++ pgrouting/test/cluster.yaml | 15 ++++ pgrouting/test/database-assert.yaml | 5 ++ pgrouting/test/database.yaml | 10 +++ 10 files changed, 296 insertions(+) create mode 100644 pgrouting/Dockerfile create mode 100644 pgrouting/README.md create mode 100644 pgrouting/metadata.hcl create mode 100644 pgrouting/test/chainsaw-test.yaml create mode 100644 pgrouting/test/check-extension-assert.yaml create mode 100644 pgrouting/test/check-extension.yaml create mode 100644 pgrouting/test/cluster-assert.yaml create mode 100644 pgrouting/test/cluster.yaml create mode 100644 pgrouting/test/database-assert.yaml create mode 100644 pgrouting/test/database.yaml diff --git a/pgrouting/Dockerfile b/pgrouting/Dockerfile new file mode 100644 index 00000000..e36fad56 --- /dev/null +++ b/pgrouting/Dockerfile @@ -0,0 +1,81 @@ +ARG BASE=ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie +FROM $BASE AS builder + +ARG PG_MAJOR +ARG EXT_VERSION + +USER 0 + +RUN set -eux && \ + # Initial system libraries + ldconfig -p | awk '{print $NF}' | grep '^/' | sort | uniq > /tmp/base-image-libs.out && \ + # Install pgRouting + apt-get update && \ + apt-get install -y --no-install-recommends \ + "postgresql-${PG_MAJOR}-pgrouting=${EXT_VERSION}" \ + "postgresql-${PG_MAJOR}-pgrouting-scripts=${EXT_VERSION}" + +# Strip the "$libdir/" prefix from LOAD and CREATE FUNCTION ... AS statements +# in the extension scripts: with imageVolume-mounted extensions +# there is no $libdir to expand, and PostgreSQL 18+ fails to resolve it during +# CREATE/ALTER EXTENSION otherwise. +# dynamic_library_path already resolves the bare module name. +# Only strip right after an opening quote, so the pattern can't accidentally +# touch unrelated text. +RUN sed -i "s/'\$libdir\//'/g" \ + /usr/share/postgresql/${PG_MAJOR}/extension/pgrouting*.sql + +# Gather pgRouting system libraries and their licenses +RUN mkdir -p /system /licenses && \ + # Get libraries + ldd /usr/lib/postgresql/${PG_MAJOR}/lib/libpgrouting*.so \ + | awk '{print $3}' | grep '^/' | sort | uniq > /tmp/all-deps.out && \ + # Extract all the libs that aren't already part of the base image + comm -13 /tmp/base-image-libs.out /tmp/all-deps.out > /tmp/libraries.out && \ + while read -r lib; do \ + resolved=$(readlink -f "$lib"); \ + dir=$(dirname "$lib"); \ + base=$(basename "$lib"); \ + # Copy the real file + cp -a "$resolved" /system/; \ + # Reconstruct all its symlinks + for file in "$dir"/"${base%.so*}.so"*; do \ + [ -e "$file" ] || continue; \ + # If it's a symlink and it resolves to the same real file, we reconstruct it + if [ -L "$file" ] && [ "$(readlink -f "$file")" = "$resolved" ]; then \ + ln -sf "$(basename "$resolved")" "/system/$(basename "$file")"; \ + fi; \ + done; \ + done < /tmp/libraries.out && \ + # Get licenses + for lib in $(find /system -maxdepth 1 -type f -name '*.so*'); do \ + # Get the name of the pkg that installed the library + pkg=$(dpkg -S "$(basename "$lib")" | grep -v "diversion by" | awk -F: '/:/{print $1; exit}'); \ + [ -z "$pkg" ] && continue; \ + mkdir -p "/licenses/$pkg" && cp -a "/usr/share/doc/$pkg/copyright" "/licenses/$pkg/copyright"; \ + done + + +FROM scratch +ARG PG_MAJOR + +# Licenses +COPY --from=builder /licenses /licenses/ +COPY --from=builder /usr/share/doc/postgresql-${PG_MAJOR}-pgrouting/copyright /licenses/postgresql-${PG_MAJOR}-pgrouting/ + +# Libraries +COPY --from=builder \ + /usr/lib/postgresql/${PG_MAJOR}/lib/libpgrouting* \ + /lib/ + +COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/bitcode/ /lib/bitcode/ + +# Share +COPY --from=builder \ + /usr/share/postgresql/${PG_MAJOR}/extension/pgrouting* \ + /share/extension/ + +# System libs +COPY --from=builder /system /system/ + +USER 65532:65532 diff --git a/pgrouting/README.md b/pgrouting/README.md new file mode 100644 index 00000000..1cca7ed0 --- /dev/null +++ b/pgrouting/README.md @@ -0,0 +1,80 @@ +# pgRouting + +[pgRouting](https://pgrouting.org/) extends the [PostGIS](https://postgis.net/)/PostgreSQL geospatial database to provide geospatial routing and other network analysis functionality. + +This image provides a convenient way to deploy and manage `pgRouting` with [CloudNativePG](https://cloudnative-pg.io/). + +> [!NOTE] +> `pgRouting` depends on `PostGIS`. When deploying `pgRouting`, you must also include the `postgis` extension image in your Cluster definition. + +## Usage + +### 1. Add the pgRouting and PostGIS extension images to your Cluster + +Define the `postgis` and `pgrouting` extensions under the `postgresql.extensions` section of your `Cluster` resource. For example: + +```yaml +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: cluster-pgrouting +spec: + imageName: ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie + instances: 1 + + storage: + size: 1Gi + + postgresql: + extensions: + - name: postgis + image: + # renovate: suite=trixie-pgdg depName=postgresql-18-postgis-3 + reference: ghcr.io/cloudnative-pg/postgis-extension:3.6.4-18-trixie + ld_library_path: + - system + env: + - name: GDAL_DATA + value: ${image_root}/share/gdal + - name: PROJ_DATA + value: ${image_root}/share/proj + - name: pgrouting + image: + # renovate: suite=trixie-pgdg depName=postgresql-18-pgrouting + reference: ghcr.io/cloudnative-pg/pgrouting:4.0.1-18-trixie + ld_library_path: + - system +``` + +### 2. Enable the extension in a database + +You can install `pgrouting` in a specific database by creating or updating a `Database` resource. Note that `postgis` must be listed before `pgrouting`: + +```yaml +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: cluster-pgrouting-app +spec: + name: app + owner: app + cluster: + name: cluster-pgrouting + extensions: + - name: postgis + # renovate: suite=trixie-pgdg depName=postgresql-18-postgis-3 extractVersion=^(?\d+\.\d+\.\d+) + version: '3.6.4' + - name: pgrouting + # renovate: suite=trixie-pgdg depName=postgresql-18-pgrouting extractVersion=^(?\d+\.\d+\.\d+) + version: '4.0.1' +``` + +### 3. Verify installation + +Once the database is ready, connect to it with `psql` and run: + +```sql +\dx +``` + +You should see `postgis` and `pgrouting` listed among the installed extensions. diff --git a/pgrouting/metadata.hcl b/pgrouting/metadata.hcl new file mode 100644 index 00000000..c99e8f8b --- /dev/null +++ b/pgrouting/metadata.hcl @@ -0,0 +1,35 @@ +metadata = { + name = "pgrouting" + sql_name = "pgrouting" + image_name = "pgrouting" + licenses = ["GPL-2.0-or-later"] + shared_preload_libraries = [] + postgresql_parameters = {} + extension_control_path = [] + dynamic_library_path = [] + ld_library_path = ["system"] + bin_path = [] + env = {} + auto_update_os_libs = true + required_extensions = ["postgis"] + create_extension = true + + versions = { + bookworm = { + "18" = { + // renovate: suite=bookworm-pgdg depName=postgresql-18-pgrouting + package = "4.0.1-1.pgdg12+1" + // renovate: suite=bookworm-pgdg depName=postgresql-18-pgrouting extractVersion=^(?\d+\.\d+\.\d+) + sql = "4.0.1" + } + } + trixie = { + "18" = { + // renovate: suite=trixie-pgdg depName=postgresql-18-pgrouting + package = "4.0.1-1.pgdg13+1" + // renovate: suite=trixie-pgdg depName=postgresql-18-pgrouting extractVersion=^(?\d+\.\d+\.\d+) + sql = "4.0.1" + } + } + } +} diff --git a/pgrouting/test/chainsaw-test.yaml b/pgrouting/test/chainsaw-test.yaml new file mode 100644 index 00000000..44d17ee7 --- /dev/null +++ b/pgrouting/test/chainsaw-test.yaml @@ -0,0 +1,28 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: verify-pgrouting-extension +spec: + timeouts: + apply: 5s + assert: 3m + delete: 30s + description: Verify pgrouting extension is properly installed + steps: + - name: Create a Cluster with the extension + try: + - apply: + file: cluster.yaml + - apply: + file: database.yaml + - assert: + file: cluster-assert.yaml + - assert: + file: database-assert.yaml + + - name: Verify extension is installed + try: + - apply: + file: check-extension.yaml + - assert: + file: check-extension-assert.yaml diff --git a/pgrouting/test/check-extension-assert.yaml b/pgrouting/test/check-extension-assert.yaml new file mode 100644 index 00000000..a7971fc7 --- /dev/null +++ b/pgrouting/test/check-extension-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: extension-installed +status: + succeeded: 1 diff --git a/pgrouting/test/check-extension.yaml b/pgrouting/test/check-extension.yaml new file mode 100644 index 00000000..46736c93 --- /dev/null +++ b/pgrouting/test/check-extension.yaml @@ -0,0 +1,28 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: extension-installed +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: PGSSLROOTCERT + - name: EXT_VERSION + value: ($values.version) + - name: DB_URI + valueFrom: + secretKeyRef: + name: (join('-', [$values.name, 'app'])) + key: uri + # renovate: datasource=docker depName=alpine/psql versioning=docker + image: alpine/psql:18.4@sha256:b3e4fc061da067813ddc5a8844b1992a50d5f1dce72d46be8ee5d0b964a3e894 + command: ['sh', '-c'] + args: + - | + set -e + DB_URI=$(echo $DB_URI | sed "s|/\*|/|") + test "$(psql "$DB_URI" -tAc "SELECT EXISTS (SELECT FROM pg_catalog.pg_extension WHERE extname = 'postgis')" -q)" = "t" + test "$(psql "$DB_URI" -tAc "SELECT EXISTS (SELECT FROM pg_catalog.pg_extension WHERE extname = 'pgrouting' AND extversion = '${EXT_VERSION}')" -q)" = "t" diff --git a/pgrouting/test/cluster-assert.yaml b/pgrouting/test/cluster-assert.yaml new file mode 100644 index 00000000..e6420cef --- /dev/null +++ b/pgrouting/test/cluster-assert.yaml @@ -0,0 +1,8 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: ($values.name) +status: + instances: 1 + readyInstances: 1 + phase: Cluster in healthy state diff --git a/pgrouting/test/cluster.yaml b/pgrouting/test/cluster.yaml new file mode 100644 index 00000000..48d6fe06 --- /dev/null +++ b/pgrouting/test/cluster.yaml @@ -0,0 +1,15 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: ($values.name) +spec: + imageName: ($values.pg_image) + instances: 1 + + storage: + size: 1Gi + + postgresql: + parameters: ($values.postgresql_parameters) + shared_preload_libraries: ($values.shared_preload_libraries) + extensions: ($values.extensions) diff --git a/pgrouting/test/database-assert.yaml b/pgrouting/test/database-assert.yaml new file mode 100644 index 00000000..9417b87b --- /dev/null +++ b/pgrouting/test/database-assert.yaml @@ -0,0 +1,5 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: (join('-', [$values.name, 'app'])) +status: ($values.database_assert_status) diff --git a/pgrouting/test/database.yaml b/pgrouting/test/database.yaml new file mode 100644 index 00000000..2d6810c2 --- /dev/null +++ b/pgrouting/test/database.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: (join('-', [$values.name, 'app'])) +spec: + name: app + owner: app + cluster: + name: ($values.name) + extensions: ($values.database_config.extensions_spec) From 49b225d0959b576c9748a1a9d0bc0c6cf6039c0f Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 29 Jul 2026 15:30:18 +0200 Subject: [PATCH 2/5] refactor(pgrouting): simplify Dockerfile to match pgvector pgRouting is self-contained: its shared library links only against standard libraries already present in the core base image, so the build stage does not need to resolve complex dependencies and stage them into the resulting container. Drop the system-library gathering and the $libdir SQL rewrite and keep a minimal. Signed-off-by: Gabriele Fedi --- pgrouting/Dockerfile | 64 ++++---------------------------------------- 1 file changed, 5 insertions(+), 59 deletions(-) diff --git a/pgrouting/Dockerfile b/pgrouting/Dockerfile index e36fad56..cc4b01d0 100644 --- a/pgrouting/Dockerfile +++ b/pgrouting/Dockerfile @@ -6,76 +6,22 @@ ARG EXT_VERSION USER 0 -RUN set -eux && \ - # Initial system libraries - ldconfig -p | awk '{print $NF}' | grep '^/' | sort | uniq > /tmp/base-image-libs.out && \ - # Install pgRouting - apt-get update && \ +RUN apt-get update && \ apt-get install -y --no-install-recommends \ - "postgresql-${PG_MAJOR}-pgrouting=${EXT_VERSION}" \ - "postgresql-${PG_MAJOR}-pgrouting-scripts=${EXT_VERSION}" - -# Strip the "$libdir/" prefix from LOAD and CREATE FUNCTION ... AS statements -# in the extension scripts: with imageVolume-mounted extensions -# there is no $libdir to expand, and PostgreSQL 18+ fails to resolve it during -# CREATE/ALTER EXTENSION otherwise. -# dynamic_library_path already resolves the bare module name. -# Only strip right after an opening quote, so the pattern can't accidentally -# touch unrelated text. -RUN sed -i "s/'\$libdir\//'/g" \ - /usr/share/postgresql/${PG_MAJOR}/extension/pgrouting*.sql - -# Gather pgRouting system libraries and their licenses -RUN mkdir -p /system /licenses && \ - # Get libraries - ldd /usr/lib/postgresql/${PG_MAJOR}/lib/libpgrouting*.so \ - | awk '{print $3}' | grep '^/' | sort | uniq > /tmp/all-deps.out && \ - # Extract all the libs that aren't already part of the base image - comm -13 /tmp/base-image-libs.out /tmp/all-deps.out > /tmp/libraries.out && \ - while read -r lib; do \ - resolved=$(readlink -f "$lib"); \ - dir=$(dirname "$lib"); \ - base=$(basename "$lib"); \ - # Copy the real file - cp -a "$resolved" /system/; \ - # Reconstruct all its symlinks - for file in "$dir"/"${base%.so*}.so"*; do \ - [ -e "$file" ] || continue; \ - # If it's a symlink and it resolves to the same real file, we reconstruct it - if [ -L "$file" ] && [ "$(readlink -f "$file")" = "$resolved" ]; then \ - ln -sf "$(basename "$resolved")" "/system/$(basename "$file")"; \ - fi; \ - done; \ - done < /tmp/libraries.out && \ - # Get licenses - for lib in $(find /system -maxdepth 1 -type f -name '*.so*'); do \ - # Get the name of the pkg that installed the library - pkg=$(dpkg -S "$(basename "$lib")" | grep -v "diversion by" | awk -F: '/:/{print $1; exit}'); \ - [ -z "$pkg" ] && continue; \ - mkdir -p "/licenses/$pkg" && cp -a "/usr/share/doc/$pkg/copyright" "/licenses/$pkg/copyright"; \ - done - + "postgresql-${PG_MAJOR}-pgrouting=${EXT_VERSION}" \ + "postgresql-${PG_MAJOR}-pgrouting-scripts=${EXT_VERSION}" FROM scratch ARG PG_MAJOR # Licenses -COPY --from=builder /licenses /licenses/ COPY --from=builder /usr/share/doc/postgresql-${PG_MAJOR}-pgrouting/copyright /licenses/postgresql-${PG_MAJOR}-pgrouting/ # Libraries -COPY --from=builder \ - /usr/lib/postgresql/${PG_MAJOR}/lib/libpgrouting* \ - /lib/ - +COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/libpgrouting* /lib/ COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/bitcode/ /lib/bitcode/ # Share -COPY --from=builder \ - /usr/share/postgresql/${PG_MAJOR}/extension/pgrouting* \ - /share/extension/ - -# System libs -COPY --from=builder /system /system/ +COPY --from=builder /usr/share/postgresql/${PG_MAJOR}/extension/pgrouting* /share/extension/ USER 65532:65532 From 3390069184c842d4c8ba31b786b523efed2555df Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 29 Jul 2026 15:40:15 +0200 Subject: [PATCH 3/5] refactor(pgrouting): drop system-lib metadata after Dockerfile simplification pgRouting links only against libraries already present in the base image, so the container no longer ships a /system directory. Clear ld_library_path and disable auto_update_os_libs accordingly, keeping metadata.hcl consistent with the simplified Dockerfile. Signed-off-by: Gabriele Fedi --- pgrouting/metadata.hcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pgrouting/metadata.hcl b/pgrouting/metadata.hcl index c99e8f8b..e88f6a08 100644 --- a/pgrouting/metadata.hcl +++ b/pgrouting/metadata.hcl @@ -7,10 +7,10 @@ metadata = { postgresql_parameters = {} extension_control_path = [] dynamic_library_path = [] - ld_library_path = ["system"] + ld_library_path = [] bin_path = [] env = {} - auto_update_os_libs = true + auto_update_os_libs = false required_extensions = ["postgis"] create_extension = true From e9510b5f58fadf3e3caa2be0a75b3c02797162ef Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 29 Jul 2026 15:58:56 +0200 Subject: [PATCH 4/5] docs(pgrouting): add SPDX headers and license section Add the CloudNativePG SPDX headers to the Dockerfile, metadata.hcl and README so the extension follows the project's licensing convention, and document the extension licensing in a "Licenses and Copyright" section. Also drop the obsolete ld_library_path from the README Cluster example, since the simplified image no longer ships a /system directory. Signed-off-by: Gabriele Fedi --- pgrouting/Dockerfile | 3 +++ pgrouting/README.md | 36 ++++++++++++++++++++++++++++++------ pgrouting/metadata.hcl | 2 ++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/pgrouting/Dockerfile b/pgrouting/Dockerfile index cc4b01d0..a4be5140 100644 --- a/pgrouting/Dockerfile +++ b/pgrouting/Dockerfile @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright © contributors to CloudNativePG, established as CloudNativePG a Series of LF Projects, LLC. +# SPDX-License-Identifier: Apache-2.0 + ARG BASE=ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie FROM $BASE AS builder diff --git a/pgrouting/README.md b/pgrouting/README.md index 1cca7ed0..da25937c 100644 --- a/pgrouting/README.md +++ b/pgrouting/README.md @@ -1,17 +1,24 @@ # pgRouting + -[pgRouting](https://pgrouting.org/) extends the [PostGIS](https://postgis.net/)/PostgreSQL geospatial database to provide geospatial routing and other network analysis functionality. +[pgRouting](https://pgrouting.org/) extends the [PostGIS](https://postgis.net/)/PostgreSQL geospatial database to +provide geospatial routing and other network analysis functionality. This image provides a convenient way to deploy and manage `pgRouting` with [CloudNativePG](https://cloudnative-pg.io/). > [!NOTE] -> `pgRouting` depends on `PostGIS`. When deploying `pgRouting`, you must also include the `postgis` extension image in your Cluster definition. +> `pgRouting` depends on `PostGIS`. When deploying `pgRouting`, you must also include the `postgis` extension image in +> your Cluster definition. ## Usage ### 1. Add the pgRouting and PostGIS extension images to your Cluster -Define the `postgis` and `pgrouting` extensions under the `postgresql.extensions` section of your `Cluster` resource. For example: +Define the `postgis` and `pgrouting` extensions under the `postgresql.extensions` section of your `Cluster` resource. +For example: ```yaml apiVersion: postgresql.cnpg.io/v1 @@ -42,13 +49,11 @@ spec: image: # renovate: suite=trixie-pgdg depName=postgresql-18-pgrouting reference: ghcr.io/cloudnative-pg/pgrouting:4.0.1-18-trixie - ld_library_path: - - system ``` ### 2. Enable the extension in a database -You can install `pgrouting` in a specific database by creating or updating a `Database` resource. Note that `postgis` must be listed before `pgrouting`: +You can install `pgrouting` in a specific database by creating or updating a `Database` resource: ```yaml apiVersion: postgresql.cnpg.io/v1 @@ -78,3 +83,22 @@ Once the database is ready, connect to it with `psql` and run: ``` You should see `postgis` and `pgrouting` listed among the installed extensions. + +--- + +## Licenses and Copyright + +`pgRouting`: + +- **Copyright:** pgRouting Contributors +- **License:** GNU General Public License v2.0 or later (`GPL-2.0-or-later`) + +All relevant license and copyright information for the `pgrouting` extension +and its dependencies are bundled within the image at: + +```text +/licenses/ +``` + +By using this image, you agree to comply with the terms of the licenses +contained therein. diff --git a/pgrouting/metadata.hcl b/pgrouting/metadata.hcl index e88f6a08..fd78d500 100644 --- a/pgrouting/metadata.hcl +++ b/pgrouting/metadata.hcl @@ -1,3 +1,5 @@ +# SPDX-FileCopyrightText: Copyright © contributors to CloudNativePG, established as CloudNativePG a Series of LF Projects, LLC. +# SPDX-License-Identifier: Apache-2.0 metadata = { name = "pgrouting" sql_name = "pgrouting" From a343be65e4c82dffc3b15bef836c15a864b31574 Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 29 Jul 2026 16:10:20 +0200 Subject: [PATCH 5/5] docs: add pgRouting to the extensions table List the pgRouting image in the root README so users can discover it alongside the other supported extensions. Signed-off-by: Gabriele Fedi --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9d47142f..c6cbd202 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ from a trusted, auditable repository | **[pgAudit](pgaudit)** | PostgreSQL audit extension | [github.com/pgaudit/pgaudit](https://github.com/pgaudit/pgaudit) | CNPG maintainers | | **[pg_crash](pg-crash)** | **Disruptive** fault injection and chaos engineering extension | [github.com/cybertec-postgresql/pg_crash](https://github.com/cybertec-postgresql/pg_crash) | CNPG maintainers | | **[pg_ivm](pg-ivm)** | Incremental View Maintenance for PostgreSQL | [github.com/sraoss/pg_ivm](https://github.com/sraoss/pg_ivm) | @shusaan | +| **[pgRouting](pgrouting)** | Geospatial routing and network analysis for PostgreSQL/PostGIS | [pgrouting.org](https://pgrouting.org/) | | | **[pgvector](pgvector)** | Vector similarity search for PostgreSQL | [github.com/pgvector/pgvector](https://github.com/pgvector/pgvector) | CNPG maintainers | | **[PostGIS](postgis)** | Geospatial database extension for PostgreSQL | [postgis.net/](https://postgis.net/) | CNPG maintainers | | **[TimescaleDB Apache-2 Edition](timescaledb-oss)** | Time-series database for PostgreSQL (open source version) | [github.com/timescale/timescaledb/](https://github.com/timescale/timescaledb/) | @shusaan |