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
16 changes: 6 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ jobs:
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
# 2.2.x releases are maintenance releases: never move `latest` off 3.x.
flavor: |
latest=false

- name: Login to Docker Hub
uses: docker/login-action@v3
Expand Down Expand Up @@ -180,6 +183,9 @@ jobs:
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
# 2.2.x releases are maintenance releases: never move `latest` off 3.x.
flavor: |
latest=false
tags: |
type=ref,event=branch
type=ref,event=pr
Expand All @@ -198,13 +204,3 @@ jobs:
if: ${{ fromJSON(env.publish) }}
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}

- name: Notify Multitudes
if: ${{ fromJSON(env.publish) }}
run: |
curl --request POST \
--fail-with-body \
--url "https://api.developer.multitudes.co/deployments" \
--header "Content-Type: application/json" \
--header "Authorization: ${{ env.MULTITUDES_ACCESS_TOKEN }}" \
--data '{"commitSha": "${{ github.sha }}", "environmentName":"dockerhub"}'
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

## [2.2.5] - 2026-10-30
## [2.2.5] - 2026-11-02

### Fixed

Expand All @@ -16,10 +16,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

- **Connection settings in transactions**: `SET CIPHERSTASH.KEYSET_ID`, `KEYSET_NAME` and `UNSAFE_DISABLE_MAPPING` now follow PostgreSQL's rules for settings in transactions. A change, including a `RESET`, `SET ... TO DEFAULT` or `DISCARD ALL`, takes effect once PostgreSQL confirms it, is kept on `COMMIT`, and is undone on `ROLLBACK` or `ROLLBACK TO SAVEPOINT`, or when the transaction fails, including the implicit transaction of a simple query or extended-protocol batch. `SET LOCAL` now lasts only until the end of the transaction. Previously Proxy kept these settings outside PostgreSQL's transactions: a rolled-back reset left Proxy with no keyset, so later writes were encrypted under `default_keyset_id` instead of the selected keyset; a rolled-back `SET CIPHERSTASH.UNSAFE_DISABLE_MAPPING = true` left mapping disabled; and `SET LOCAL` was treated as a plain `SET`. Setting names are now matched as PostgreSQL matches them, ignoring case and quoting, and `UNSAFE_DISABLE_MAPPING` accepts every PostgreSQL boolean spelling. A `SET CIPHERSTASH.*` that Proxy cannot honour, such as an unknown setting name or a value it cannot interpret, is now refused with an error instead of being ignored. A simple query that Proxy rewrites now forwards every statement in it; previously statements Proxy did not map, such as a `SET`, could be dropped from a query that also encrypted values. A prepared statement is now refused with SQLSTATE `26000` if mapping has been turned on or off since it was prepared or bound, or if the keyset has changed and it holds values encrypted under the previous keyset, for example after a rollback undid the change it was prepared under; prepare it again to run it under the new settings. A statement or message that Proxy refuses now fails the batch, and an open transaction, in PostgreSQL as well, as an error from PostgreSQL would. Previously Proxy answered a refused extended-protocol batch itself, so statements earlier in the batch could still commit and the client's transaction carried on as if nothing had failed. A statement pipelined after a query or batch that may change these settings now waits for PostgreSQL to answer it, so it is mapped under the settings PostgreSQL confirmed. Previously Proxy assumed the change succeeded, so a `SET` that failed, or a `SET LOCAL` that ended with its implicit transaction, still applied to the statements sent after it.

- **`COPY ... FROM STDIN`**: Proxy now forwards a `COPY ... FROM STDIN` into a table with no encrypted columns, with its copy data, so `psql`'s `\copy` and driver `COPY` APIs can bulk-load plaintext tables through Proxy. Previously Proxy refused the statement as invalid SQL unless it ended with `;`, with or without an encryption configuration. A `COPY ... FROM` into an encrypted column is now refused with an error that names the column, as Proxy does not encrypt `COPY` data; previously a `COPY` from a file or program was forwarded with its plaintext. When encrypted columns are configured, a `COPY ... FROM` into a table or column that Proxy has not loaded, or into a table name that more than one schema has, is refused, as Proxy cannot tell whether it is encrypted. Statements after a `COPY ... FROM STDIN;` in the same simple query are now checked and encrypted like any other; previously Proxy read them as copy data and forwarded them unchanged, so a plaintext `INSERT` into an encrypted column could reach PostgreSQL. A simple query that has a `COPY` and a statement Proxy encrypts is refused, and the `COPY` must be sent in a query of its own. A `COPY (INSERT ... RETURNING ...) TO STDOUT`, or a `COPY` of another query that writes, is refused when encrypted columns are configured; previously Proxy forwarded its values as plaintext. Proxy now parses every `COPY`, so it refuses as invalid SQL the few `COPY` options its SQL parser does not support, such as `WHERE`, `HEADER MATCH` and `ON_ERROR`.
- **`COPY ... FROM STDIN`**: Proxy now forwards a `COPY ... FROM STDIN` into a table with no encrypted columns, with its copy data, so `psql`'s `\copy` and driver `COPY` APIs can bulk-load plaintext tables through Proxy. Previously Proxy refused the statement as invalid SQL unless it ended with `;`, with or without an encryption configuration. A `COPY ... FROM` into an encrypted column is now refused with an error that names the column, as Proxy does not encrypt `COPY` data; previously a `COPY` from a file or program was forwarded with its plaintext. When encrypted columns are configured, a `COPY ... FROM` into a table or column that Proxy has not loaded, or into a table name that more than one schema has, is refused, as Proxy cannot tell whether it is encrypted. Statements after a `COPY ... FROM STDIN;` in the same simple query are now checked and encrypted like any other; previously Proxy read them as copy data and forwarded them unchanged, so a plaintext `INSERT` into an encrypted column could reach PostgreSQL. A simple query that has a `COPY` and a statement Proxy encrypts is refused, and the `COPY` must be sent in a query of its own. A `COPY (INSERT ... RETURNING ...) TO STDOUT`, or a `COPY` of another query that writes, is refused when encrypted columns are configured; previously Proxy forwarded its values as plaintext. Proxy now parses every `COPY`, so it refuses as invalid SQL the few `COPY` options its SQL parser does not support, such as `WHERE`, `HEADER MATCH` and `ON_ERROR`. A `COPY ... FROM` prepared while mapping is disabled is refused if mapping has been turned back on before it runs, as other prepared statements are, since Proxy did not check it when it was prepared.

- **Plaintext forwarded beside a statement Proxy cannot type check**: When encrypted columns are configured, Proxy now refuses a write that it cannot type check, such as an `INSERT` into a table it has not loaded, instead of forwarding it to PostgreSQL unchanged. Such a write is still forwarded when Proxy knows that every table it writes to has no encrypted columns. Proxy also refuses a simple query that has a statement it cannot type check together with a statement it needs to encrypt or decrypt. Previously, with mapping errors off (the default), Proxy forwarded the whole query as written, so an `INSERT` into an encrypted column in the same query reached PostgreSQL with its plaintext values. A read that Proxy cannot type check is still forwarded unchanged when it is sent in a query of its own or only with statements that Proxy does not need to map. A statement that Proxy forwards unchanged is sent as written, so a plaintext value that it compares with an encrypted column still reaches the database.

- **Encryption results checked before use**: Proxy now refuses a statement when the encryption service returns fewer encrypted values than the values it was asked to encrypt. Previously the parameters left without an encrypted value were sent to PostgreSQL as written, so a misbehaving encryption service could cause plaintext to reach the database.

- **Bind to a statement Proxy did not see prepared**: Proxy now refuses a `Bind` that names a prepared statement it did not see prepared on the connection, with SQLSTATE `26000`, PostgreSQL's own code for a missing prepared statement. Previously Proxy sent the bound values as written, so if it had lost track of a statement that writes an encrypted column, the values reached PostgreSQL unencrypted. This includes a statement whose `Parse` Proxy refused, which PostgreSQL never prepared. A statement prepared with SQL `PREPARE` can no longer be bound with a `Bind` message through Proxy.

- **Plaintext in `INSERT ... ON CONFLICT DO UPDATE`**: Proxy now encrypts a value assigned to an encrypted column in the `DO UPDATE SET` clause of an upsert. Previously the clause was not type checked, so a literal or parameter assigned to an encrypted column there reached PostgreSQL as plaintext. `excluded.<column>` now carries the column's encrypted type, and an `ON CONFLICT` target on an encrypted column is refused, as a conflict judged on randomised ciphertext would never fire.

- **Database error detail in Proxy's logs**: logged database errors again include the message PostgreSQL returned, not just the error kind. The upgraded PostgreSQL client library stopped appending the underlying cause when an error is rendered as text, which left entries such as `Database connection error` reading only `db error`. Proxy now renders the cause itself, so the server's message is back in the log line.

### Security

- **Dependency updates**: Updated `rustls` to 0.23.46, `rustls-webpki` to 0.103.16, `webpki-root-certs` to 1.0.11, `aws-lc-rs` to 1.18.2 (with `aws-lc-sys` 0.46.0), `tokio-postgres` to 0.7.18, `postgres-protocol` to 0.6.12, `tokio` to 1.51.6, `h2` to 0.4.20, `crossbeam-epoch` to 0.9.21, `rand` to 0.9.3 and 0.10.2, `quinn-proto` to 0.11.15, `hickory-proto` and `hickory-resolver` to 0.26.3 (with `reqwest` 0.13.4), and `diesel` to 2.3.12, to pick up the fixes for published security advisories in those crates. No configuration change is required.

## [2.2.4] - 2026-06-18

### Fixed
Expand Down
Loading
Loading