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
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ Next.js also compiles `src/instrumentation.ts` for the Edge runtime, so Node.js-

`installer/` is a standalone Bun 1.4.2 package with its own `package.json`, `bun.lock` and tests.
Platform's lint, Vitest run and Docker image ignore it.
Release 1.1.1 installs in Docker mode on one x86_64 Linux host with the installer, and on Kubernetes with the Helm chart `charts/libredb-platform`, whose jobs run the installer's Kubernetes-mode code; the installer's own `preflight`, `plan`, `apply`, `verify` and `db-script` refuse `mode: kubernetes`.
Release 1.2.0 installs in Docker mode on one x86_64 Linux host with the installer, and on Kubernetes with the Helm chart `charts/libredb-platform`, whose jobs run the installer's Kubernetes-mode code; the installer's own `preflight`, `plan`, `apply`, `verify` and `db-script` refuse `mode: kubernetes`.
`docs/deploy/install-docker.md` is the customer's install guide and `installer/README.md` the reference of every command and field, so a change to a command, a default or a prerequisite updates both.

```bash
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Write to [info@libredb.org](mailto:info@libredb.org) or join the waiting list at

## Install

Platform 1.1.0 is the current release, published as the image `ghcr.io/libredb/libredb-platform`, and pairs with LibreDB Studio 1.0.0.
Platform 1.1.0 is the current release, published as the image `ghcr.io/libredb/libredb-platform`, and pairs with LibreDB Studio 1.1.0.
It installs with Docker on one x86_64 Linux host: the installer deploys PostgreSQL, Keycloak, Platform, Studio and a Caddy edge, and can use an existing PostgreSQL server or Keycloak instead.
On Kubernetes, the Helm chart [`charts/libredb-platform`](charts/libredb-platform) installs the same, from the Helm repository `https://libredb.org/libredb-platform/` or `oci://ghcr.io/libredb/charts/libredb-platform`, as the [Kubernetes install guide](docs/deploy/install-kubernetes.md) describes.
Each release is tested with Docker Compose on a plain host and on a host that runs a Docker Swarm, and with the chart on vanilla Kubernetes, on clusters that Rancher manages and on OpenShift 4.
Expand Down
6 changes: 3 additions & 3 deletions charts/libredb-platform/Chart.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
dependencies:
- name: libredb-studio
repository: https://libredb.org/libredb-studio/
version: 0.1.100
digest: sha256:a56f4096de2bd4d02e73a5b984ba8040490565a767be05a123ffb2abb88a92d6
generated: "2026-10-20T02:08:21.66270654+03:00"
version: 0.1.103
digest: sha256:5a90877a3308b571e8eeeeb72541cce1911714937b0ac908b47764241b8e792f
generated: "2026-10-24T20:40:23.343256639+03:00"
18 changes: 10 additions & 8 deletions charts/libredb-platform/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ type: application
# The chart ships in the installer's release, so version and appVersion are both that release, whose images and
# Studio chart it pins (installer/release/release.config.json, which installer/test/unit/kubernetes/chart.test.ts
# compares, together with installer/package.json).
version: 1.1.1
appVersion: "1.1.1"
version: 1.2.0
appVersion: "1.2.0"
kubeVersion: ">=1.28.0-0"
home: https://libredb.org/platform/
icon: https://raw.githubusercontent.com/libredb/libredb-studio/main/public/logo.svg
Expand All @@ -34,17 +34,19 @@ annotations:
artifacthub.io/license: Elastic-2.0
artifacthub.io/containsSecurityUpdates: "false"
artifacthub.io/changes: |
- kind: changed
description: "LibreDB Studio 1.1.0 under governance, from the Studio chart 0.1.103; LibreDB Platform stays at 1.1.0"
- kind: added
description: "First release of the chart, with LibreDB Platform 1.1.0 and LibreDB Studio 1.0.0 under governance"
description: "Studio 1.1.0 accepts an identity provider access token as a bearer session for native clients, under the same governance rule as a session cookie"
- kind: added
description: "A managed or an external PostgreSQL and Keycloak, Argo CD hooks, OpenShift restricted-v2, seal key rotation, backup and restore, and an install without network access"
- kind: added
description: "Platform 1.1.0 adds the bearer API under /api/v1 for LibreDB Mobile"
description: "With mobile.enabled set to true, a Docker-mode install lets the LibreDB Mobile client use Studio and the Platform API under /api/v1; this chart does not create the mobile client yet"
- kind: fixed
description: "Studio 1.1.0 asks before a write inside a CTE or under EXPLAIN ANALYZE runs, and reads primary and foreign keys for a SELECT-only PostgreSQL role"
artifacthub.io/images: |
- name: libredb-platform
image: ghcr.io/libredb/libredb-platform:1.1.0@sha256:56d89d9cbb7fde237a1e8af51bb155c276352bf1f7719f8c651b9f5b37213d92
- name: libredb-studio
image: ghcr.io/libredb/libredb-studio:1.0.0@sha256:0cb0177dd2789534f2dbfbc6673104ec0ce70ee82815f5fe9bec5efe3d329ce3
image: ghcr.io/libredb/libredb-studio:1.1.0@sha256:e91183def05f4c13703c77363ec51ad68bfa45b1b1d3b92dc53c331b67e53d2c
- name: postgres
image: docker.io/library/postgres:18.6@sha256:74935e72241653ca55e0414067e6d8763aceb8a810eb51b452253ec3dcfc4336
- name: keycloak
Expand All @@ -59,6 +61,6 @@ annotations:
dependencies:
- name: libredb-studio
alias: studio
version: 0.1.100
version: 0.1.103
repository: https://libredb.org/libredb-studio/
condition: studio.enabled
Binary file modified charts/libredb-platform/files/libredb-jobs.cjs.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion charts/libredb-platform/tests/e2e/run-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ else
fi

step "chart dependencies"
if [ ! -f "$chart/charts/libredb-studio-0.1.100.tgz" ]; then
if [ ! -f "$chart/charts/libredb-studio-0.1.103.tgz" ]; then
# helm dependency build takes Chart.lock's Studio chart only from a repository Helm knows.
helm repo add libredb-studio https://libredb.org/libredb-studio/ >/dev/null 2>&1 || true
helm dependency build "$chart"
Expand Down
2 changes: 1 addition & 1 deletion charts/libredb-platform/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ studio:
fullnameOverride: libredb-studio
image:
repository: ghcr.io/libredb/libredb-studio
tag: "1.0.0@sha256:0cb0177dd2789534f2dbfbc6673104ec0ce70ee82815f5fe9bec5efe3d329ce3"
tag: "1.1.0@sha256:e91183def05f4c13703c77363ec51ad68bfa45b1b1d3b92dc53c331b67e53d2c"
authProvider: oidc
governance:
enabled: true
Expand Down
8 changes: 4 additions & 4 deletions docs/deploy/install-docker.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Install LibreDB with Docker

This guide installs LibreDB 1.1.1 on one x86_64 Linux host with Docker.
This guide installs LibreDB 1.2.0 on one x86_64 Linux host with Docker.
The install is tested with Docker Compose on a plain host and on a host that runs a Docker Swarm, such as one of Dokploy or CapRover.
The installer, `libredb-installer`, runs on that host as root and deploys PostgreSQL, Keycloak, LibreDB Platform, LibreDB Studio and a Caddy edge as the Docker Compose project `libredb`.
The guide takes the shortest path: a PostgreSQL and a Keycloak that the installer runs itself, one DNS name per app, and certificates from the installer's internal CA.
Expand Down Expand Up @@ -62,7 +62,7 @@ The installer treats the token as a secret and never prints it, so keep the file
The installer is one binary, published with a file of checksums on this repository's [GitHub releases](https://github.com/libredb/libredb-platform/releases):

```sh
V=1.1.1
V=1.2.0
B=https://github.com/libredb/libredb-platform/releases/download/installer-v$V
mkdir -p ~/libredb-$V && cd ~/libredb-$V
curl -fL -O "$B/libredb-installer-linux-x64" -O "$B/SHA256SUMS"
Expand All @@ -71,7 +71,7 @@ chmod 0755 libredb-installer-linux-x64
./libredb-installer-linux-x64 version
```

Expected: `sha256sum` prints `libredb-installer-linux-x64: OK`, and `version` prints `release 1.1.1`.
Expected: `sha256sum` prints `libredb-installer-linux-x64: OK`, and `version` prints `release 1.2.0`.
`sha256sum -c` needs no account, and it shows that the download is complete and matches the release's checksums.
To check that this repository's release workflow built the binary, verify its attestation with the [GitHub CLI](https://cli.github.com), which needs a GitHub login (`gh auth login`):

Expand Down Expand Up @@ -134,7 +134,7 @@ The configuration never holds a secret or a license token itself, only the paths
## Check the host and the configuration

```sh
cd ~/libredb-1.1.1
cd ~/libredb-1.2.0
./libredb-installer-linux-x64 validate -c /etc/libredb/libredb.yaml
./libredb-installer-linux-x64 preflight -c /etc/libredb/libredb.yaml
./libredb-installer-linux-x64 plan -c /etc/libredb/libredb.yaml
Expand Down
2 changes: 1 addition & 1 deletion docs/deploy/install-kubernetes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Install LibreDB on Kubernetes

This guide installs LibreDB 1.1.1 on a Kubernetes cluster with the Helm chart [`charts/libredb-platform`](../../charts/libredb-platform).
This guide installs LibreDB 1.2.0 on a Kubernetes cluster with the Helm chart [`charts/libredb-platform`](../../charts/libredb-platform).
The chart is tested on vanilla Kubernetes, on clusters that Rancher manages and on OpenShift 4.
The chart deploys LibreDB Platform, its migrate job and LibreDB Studio under governance, and by default a PostgreSQL server and a Keycloak that it runs itself.
It is the installer's Kubernetes mode driven by Helm: the chart renders its values as an installation configuration of `mode: kubernetes`, and its jobs run the installer's own code on it, so a Helm install gets the same secrets, certificates, environments, PostgreSQL provisioning and Keycloak realm as a [Docker install](install-docker.md) of the same configuration.
Expand Down
4 changes: 2 additions & 2 deletions docs/platform-studio-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

This page explains, with diagrams, how LibreDB Platform governs LibreDB Studio in an on-prem install.
It is a reading aid.
The contract itself is [Studio's `docs/GOVERNANCE.md`](https://github.com/libredb/libredb-studio/blob/1.0.0/docs/GOVERNANCE.md).
Every diagram and table follows the code of Platform in this repository and of [Studio 1.0.0](https://github.com/libredb/libredb-studio/releases/tag/1.0.0).
The contract itself is [Studio's `docs/GOVERNANCE.md`](https://github.com/libredb/libredb-studio/blob/1.1.0/docs/GOVERNANCE.md).
Every diagram and table follows the code of Platform in this repository and of [Studio 1.1.0](https://github.com/libredb/libredb-studio/releases/tag/1.1.0).
Terms such as snapshot, envelope, seal canary, governance mode and `seed:<id>` are defined in the [glossary](#14-glossary) at the end.

Five ideas carry the whole design:
Expand Down
2 changes: 1 addition & 1 deletion installer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ The claim `libredb_roles` reaches its ID token, from which the app reads its rol
`studio.env` gets `OIDC_BEARER_AUDIENCE=libredb-studio-api` and `OIDC_BEARER_CLIENT_IDS=libredb-mobile`, so Studio accepts an access token only when its `aud` holds that audience and its `azp` is `libredb-mobile`.
Under governance Studio applies to that token the same sign-in rule as to a session cookie, and because the realm is the one Studio's web sign-in uses, its `sub` matches the subject of Platform's grants.
The bearer channel needs a Studio release that contains [libredb-studio#1914](https://github.com/libredb/libredb-studio/pull/1914); a Studio without it ignores both variables and the `Authorization` header, so the app gets `401` on every call.
This release pins Studio 1.0.0, which does not contain it.
This release pins Studio 1.1.0, which contains it.
`platform.env` gets `PLATFORM_API_AUDIENCE=libredb-platform-api` and `PLATFORM_API_CLIENT_IDS=libredb-mobile`, so Platform's API accepts an access token only when its `aud` holds that audience and its `azp` is `libredb-mobile`, and only for an account with the role `admin`, as [docs/api/v1.md](../docs/api/v1.md) describes.
The bearer API needs a Platform release that contains [#24](https://github.com/libredb/libredb-platform/issues/24); a Platform without it ignores both variables, so every call under `/api/v1` gets `404`.
This release pins Platform 1.1.0, which contains it.
Expand Down
3 changes: 2 additions & 1 deletion installer/contracts/env-inventory.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -409,13 +409,14 @@ variables:

# Must be unset or false in Studio governance mode, because Studio's boot checks refuse them (Studio's GOVERNANCE.md,
# Boot checks). LIBREDB_MCP_ENABLED and LIBREDB_AGENT_ENABLED stay here until Studio runs MCP and the agent under
# governance.
# governance. Studio 1.1.0 refuses OIDC_ROLE_PREFIX as well, which it reads only for seed connections.
studioForbidden:
- ALLOW_CUSTOM_CONNECTIONS
- LIBREDB_EMBEDDED_SAMPLE
- SQLITE_EMBEDDED_SAMPLE
- SEED_CONFIG_PATH
- SEED_DISCOVERY_PATH
- OIDC_ROLE_PREFIX
- ADMIN_PASSWORD
- USER_PASSWORD
- LAUNCH_TOKEN_SECRET
Expand Down
2 changes: 1 addition & 1 deletion installer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "libredb-installer",
"version": "1.1.1",
"version": "1.2.0",
"private": true,
"license": "Elastic-2.0",
"type": "module",
Expand Down
53 changes: 53 additions & 0 deletions installer/release/history/1.2.0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"version": "1.2.0",
"images": {
"platform": {
"repository": "ghcr.io/libredb/libredb-platform",
"version": "1.1.0",
"digest": "sha256:56d89d9cbb7fde237a1e8af51bb155c276352bf1f7719f8c651b9f5b37213d92"
},
"studio": {
"repository": "ghcr.io/libredb/libredb-studio",
"version": "1.1.0",
"digest": "sha256:e91183def05f4c13703c77363ec51ad68bfa45b1b1d3b92dc53c331b67e53d2c"
},
"keycloak": {
"repository": "quay.io/keycloak/keycloak",
"version": "26.8.1",
"digest": "sha256:79c623a22abacf3fe6c00a5fb30f5b7843d717b234033b80995891c06116d244"
},
"postgres": {
"repository": "docker.io/library/postgres",
"version": "18.6",
"digest": "sha256:74935e72241653ca55e0414067e6d8763aceb8a810eb51b452253ec3dcfc4336"
},
"edge": {
"repository": "docker.io/library/caddy",
"version": "2.11.7",
"digest": "sha256:685ae3d7c34d9b5f8caeddc5d14051db7bbd88ff1f5a2fa0c16bd8ca328fb7af"
}
},
"studioChart": {
"name": "libredb-studio",
"version": "0.1.103",
"repository": "https://libredb.org/libredb-studio/",
"sha256": "2998a9612e175f6cada18a5d704282e778706e542377dcd22a3eee1ee77ccf2c"
},
"minimums": {
"dockerEngine": "28.0.0",
"compose": "2.24.0",
"kubernetes": "1.28.0"
},
"studio": {
"logoutHintVerified": true,
"reportedVersion": "1.1.0"
},
"contracts": {
"platformPublishes": [
1
],
"studioSupports": [
1
]
}
}
12 changes: 6 additions & 6 deletions installer/release/release.config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.1.1",
"version": "1.2.0",
"images": {
"platform": {
"repository": "ghcr.io/libredb/libredb-platform",
Expand All @@ -8,8 +8,8 @@
},
"studio": {
"repository": "ghcr.io/libredb/libredb-studio",
"version": "1.0.0",
"digest": "sha256:0cb0177dd2789534f2dbfbc6673104ec0ce70ee82815f5fe9bec5efe3d329ce3"
"version": "1.1.0",
"digest": "sha256:e91183def05f4c13703c77363ec51ad68bfa45b1b1d3b92dc53c331b67e53d2c"
},
"keycloak": {
"repository": "quay.io/keycloak/keycloak",
Expand All @@ -29,9 +29,9 @@
},
"studioChart": {
"name": "libredb-studio",
"version": "0.1.100",
"version": "0.1.103",
"repository": "https://libredb.org/libredb-studio/",
"sha256": "f9bf702a427bfd402f1d9525ff0be0f36c5e2618a77668fc9d5562faddc890b0"
"sha256": "2998a9612e175f6cada18a5d704282e778706e542377dcd22a3eee1ee77ccf2c"
},
"minimums": {
"dockerEngine": "28.0.0",
Expand All @@ -40,7 +40,7 @@
},
"studio": {
"logoutHintVerified": true,
"reportedVersion": "1.0.0"
"reportedVersion": "1.1.0"
},
"contracts": {
"platformPublishes": [1],
Expand Down
1 change: 1 addition & 0 deletions installer/src/contracts/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ export const STUDIO_FORBIDDEN = [
"SQLITE_EMBEDDED_SAMPLE",
"SEED_CONFIG_PATH",
"SEED_DISCOVERY_PATH",
"OIDC_ROLE_PREFIX",
"ADMIN_PASSWORD",
"USER_PASSWORD",
"LAUNCH_TOKEN_SECRET",
Expand Down
8 changes: 8 additions & 0 deletions installer/test/integration/contracts/preflight-drift.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,14 @@ describe("rendered environments against the pinned app images", () => {
LONG,
);

test(
"the Studio image exits 1 naming OIDC_ROLE_PREFIX when it is set",
async () => {
await expectStudioRefusal("studio-role-prefix", { ...studioEnv, OIDC_ROLE_PREFIX: "libredb_" }, "OIDC_ROLE_PREFIX");
},
LONG,
);

test(
"the Studio image exits 1 naming GOVERNANCE_PRIVATE_KEYS_FILE when the keyring holds 17 keys",
async () => {
Expand Down
4 changes: 4 additions & 0 deletions installer/test/unit/contracts/studio-env.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ describe("renderStudioEnv", () => {
for (const key of STUDIO_FORBIDDEN) expect(Object.keys(env)).not.toContain(key);
});

test("lists OIDC_ROLE_PREFIX among the variables that must be unset, because Studio 1.1.0 refuses it in governance mode", () => {
expect(STUDIO_FORBIDDEN).toContain("OIDC_ROLE_PREFIX");
});

test("writes the governance values of contracts/env-inventory.yaml", () => {
const env = renderStudioEnv(desiredFixture(), inputs);
const url =
Expand Down
4 changes: 4 additions & 0 deletions installer/test/unit/release/manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ describe("release manifest", () => {
const raw: unknown = JSON.parse(readFileSync(join(import.meta.dir, "../../../release/release.config.json"), "utf8"));
const manifest = parseReleaseManifest(raw);
expect(manifest.images.platform.repository).toBe("ghcr.io/libredb/libredb-platform");
expect(manifest.version).toBe("1.2.0");
expect(manifest.images.platform.version).toBe("1.1.0");
expect(manifest.images.studio.version).toBe("1.1.0");
expect(manifest.studioChart.version).toBe("0.1.103");
expect(manifest.studio.reportedVersion).toBe("1.1.0");
expect(manifest.images.keycloak.version).toBe("26.8.1");
expect(manifest.images.postgres.version).toBe("18.6");
// The "logout hint" test of e2e/interop.spec.ts passed against the pinned Keycloak.
Expand Down
2 changes: 2 additions & 0 deletions tests/fixtures/governance/GOVERNANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ Under governance the identity provider at `OIDC_ISSUER` is the only way into Stu
Studio checks the session of every request against these rules:

- A session counts only when Studio's OIDC callback minted it: it carries the ID token's `sub` as a non-empty subject and the ID token's `iss` as its issuer, and the issuer equals `OIDC_ISSUER`, the two compared as URLs with one trailing slash ignored.
- A native client's identity provider access token ([OIDC.md](./OIDC.md#bearer-access-tokens-for-native-clients)) counts under the same rule, with the access token's `sub` and `iss`, and its own `iat` as its issue time.
- A password, passkey or launch session carries no subject and is refused, and so is a session whose subject is empty or whose issuer is not `OIDC_ISSUER`.
With `OIDC_ISSUER` unset or not a URL every session is refused, and a changed `OIDC_ISSUER` ends the sessions of the previous issuer.
- A session issued at or before its subject's latest `revoked_before` in [`bridge.session_revocations_v1`](#row-semantics) is refused, typically within a second of the commit that adds the row, because its change notification reloads the snapshot.
Expand Down Expand Up @@ -708,6 +709,7 @@ Capture follows `queryLog.statementCapture`, which is `none` while the control p
- `full` keeps every other secret written into a statement, such as a Redis `AUTH` argument, and an error text that quotes a statement in the driver's own words can carry one, so choose it only where the statements themselves must be kept.
- A refused request whose connection did not resolve, such as one for a connection the caller holds no grant on, stores no statement and no error text in any mode, because the engine that would read them is unknown.
- In every mode `statement_type` is `SELECT`, `INSERT`, `UPDATE` or `DELETE` from the keyword that operates the statement, also behind a `WITH`, `DDL` for `CREATE`, `ALTER`, `DROP` and `TRUNCATE`, and `OTHER` for any other statement, for a unit without text and for every engine whose statements are not SQL.
A `SELECT` behind a `WITH` whose CTE body writes takes the type of that write, so `WITH d AS (DELETE … RETURNING *) SELECT * FROM d` is `DELETE`, and a `MERGE` or `UPSERT` body is `OTHER`.
A `profile` row is `SELECT` and a `key-scan` row `OTHER` on every engine, because their statement names what was read rather than being a statement the user wrote.
- The statement of a `profile` or `key-scan` row is captured like any statement of its engine, so under `redacted` a quoted SQL name is kept while a Redis page request keeps only `SCAN` and one `?` per argument, and no cursor or pattern value reaches the row.
- A request the admission gate refuses records one `refused` row with its route's source, the connection's engine and access level, and `error_code` `AUDIT_UNAVAILABLE`.
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/governance/GOVERNANCE.md.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
c7712e7fe13a6d93368b31b2ba93af791c09f0d37a4df2e033b64a98a9309cf3 GOVERNANCE.md
b40aab2821c29a99497f8d3e3d4d0f1e66080425b93e395e52d69c595cd489f9 GOVERNANCE.md
2 changes: 1 addition & 1 deletion tests/fixtures/governance/STUDIO_TAG
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.0
1.1.0
Loading