# v0.19.0 — Security Hardening and Distribution

> **Full technical details:** [v0.19.0.md-full.md](v0.19.0.md-full.md)

**Status: ✅ Released** | **Scope: Medium** (~3–4 weeks)

> Ownership and privilege checks for all SQL functions, WAL decoder
> correctness fixes, a scheduler O(n²) performance fix at scale, and
> wide distribution: PGXN stable release, Docker Hub automation, and
> apt/rpm packages.

---

## What problem does this solve?

As pg_trickle moved toward production use in multi-user and multi-tenant
PostgreSQL deployments, security gaps became important to address: any
database user could call functions that should only be callable by the
stream table's owner. The WAL decoder had correctness issues under specific
conditions. The scheduler slowed quadratically as stream table counts grew.
And wider distribution — through packaging systems that operators already
use — became important.

---

## Ownership and Privilege Checks

All SQL functions in pg_trickle now enforce that the caller is the owner of
the stream table being operated on (or a superuser). Previously, a low-
privilege database user could, in principle, call `drop_stream_table` or
`alter_stream_table` on a stream table they did not own.

Functions are categorised into three privilege levels:

- **Owner-only** — `drop_stream_table`, `alter_stream_table`, `pause_source`
- **Authenticated user** — `create_stream_table` (ownership is assigned at
  creation)
- **Public read** — diagnostic views like `pg_stat_stream_tables`

*In plain terms:* stream tables are now properly secured — only their owners
can modify or drop them, just like regular PostgreSQL tables.

---

## WAL Decoder Correctness Fixes

Several correctness issues in the WAL-based change decoder were resolved:

- The decoder now correctly handles the `pk_hash` for rows where the primary
  key spans nullable columns
- A race condition between DROP TABLE and an in-progress WAL decode was
  resolved
- Large transactions (many thousands of rows in a single transaction) no
  longer cause the decoder to lose rows

---

## Scheduler O(n²) Fix

The background scheduler's main dispatch loop was performing an O(n²)
operation: for each stream table to refresh, it was scanning the full list
of all stream tables to find its dependencies. With 200 stream tables this
was barely noticeable; with 500+ it became a measurable bottleneck.

The dependency lookup was restructured to O(1) using a pre-built index,
making the scheduler's overhead constant regardless of the number of stream
tables.

---

## PgBouncer Guard

A new startup check verifies that the PgBouncer configuration is compatible
with pg_trickle when a PgBouncer connection is detected. If an incompatible
configuration is found, a clear error message explains the required changes.

---

## Read-Replica Safety

Stream tables can now be configured with a `read_replica_safe => true` flag,
which causes all reads to be directed to a PostgreSQL streaming replica if
one is configured. This offloads read traffic from the primary server.

---

## PGXN Stable Release

pg_trickle is now listed on **PGXN** (the PostgreSQL Extension Network) as
a stable release, making it discoverable through the standard PostgreSQL
extension ecosystem.

---

## Docker Hub Automation

Official Docker images are now automatically built and published to
**Docker Hub** on each release, alongside the existing GitHub Container
Registry images. This is the preferred image registry for most Docker and
Kubernetes users.

---

## apt and rpm Packages

Pre-built binary packages are now available for:

- **apt** (Debian, Ubuntu) via a hosted package repository
- **rpm** (RHEL, CentOS, Fedora) via a hosted package repository

Installation is as simple as adding the repository and running
`apt install postgresql-18-pgtrickle`.

---

## Scope

v0.19.0 is a security, correctness, and distribution release. The privilege
checks are essential for multi-user deployments. The packaging improvements
dramatically lower the barrier to installation. Together, these make v0.19.0
the first release that is straightforward to adopt in a standard enterprise
PostgreSQL environment.
