feat: add Database-Gateway Cloudron package (Infrastructure) [#639]
Database Gateway 0.24.0 as the 12th package: multi-stage Go build (CGO required by the libpg_query parser, hence an alpine:3.23 runtime matching upstream), native OIDC wired to the Cloudron platform identity provider, postgresql addon storage with goose migrations applied at start, jq-generated config + OPA policy seeded to /app/data. Verified end-to-end against a throwaway postgres (migrations, policy compile, startup to the OIDC handoff). Docs gardened to 12 packages. Ticket: https://projects.knownelement.com/issues/639
This commit is contained in:
+74
-1
@@ -4,7 +4,7 @@
|
|||||||
**Project**: TSYSDevStack-SupportStack-Cloudron
|
**Project**: TSYSDevStack-SupportStack-Cloudron
|
||||||
**Goal**: Package ~57 applications for Cloudron PaaS platform
|
**Goal**: Package ~57 applications for Cloudron PaaS platform
|
||||||
**Start Date**: 2025-01-24
|
**Start Date**: 2025-01-24
|
||||||
**Current Status**: 11/~57 packages completed (~19%)
|
**Current Status**: 12/~57 packages completed (~21%)
|
||||||
|
|
||||||
## Completed Packages
|
## Completed Packages
|
||||||
|
|
||||||
@@ -893,6 +893,79 @@ traversal (frp/ngrok class, Rust); this package runs the **server** side
|
|||||||
|
|
||||||
**Commit**: `feat: add Rathole Cloudron package (Infrastructure) [#650]`
|
**Commit**: `feat: add Rathole Cloudron package (Infrastructure) [#650]`
|
||||||
|
|
||||||
|
### 12. Database Gateway (Infrastructure) ✅
|
||||||
|
**Date**: 2026-09-01
|
||||||
|
**Application**: Database Gateway (dbgw) — policy-checked web gateway to
|
||||||
|
PostgreSQL databases (OIDC login, OPA-authorized queries, cached results)
|
||||||
|
**Package Size**: 93.7MB (alpine runtime; smallest package so far)
|
||||||
|
**Port**: 8080 (httpPort, single listener — web UI + LRPC API)
|
||||||
|
**Addons**: localstorage, postgresql (16)
|
||||||
|
|
||||||
|
**Key Learnings**:
|
||||||
|
- **Auth gate verdict**: NATIVE OIDC, the preferred row — no local users,
|
||||||
|
no LDAP, the only login path is an OIDC provider. Perfect fit for the
|
||||||
|
Cloudron platform provider: `CLOUDRON_OIDC_ISSUER` / `CLIENT_ID` /
|
||||||
|
`CLIENT_SECRET` are written into `users.*` of the seeded config;
|
||||||
|
redirect URL derives from `CLOUDRON_APP_ORIGIN` + `/auth/callback`;
|
||||||
|
roles map from the `groups` claim (Cloudron `admins` → admin,
|
||||||
|
`users` → user). First package in the set to consume the platform
|
||||||
|
OIDC env vars end-to-end
|
||||||
|
- **cgo is load-bearing**: the SQL parser is a libpg_query cgo binding —
|
||||||
|
`CGO_ENABLED=0` fails to compile (`undefined: pg.Parse`). The binary
|
||||||
|
therefore links musl and will not exec on Ubuntu/glibc bases (fails
|
||||||
|
with a misleading "no such file or directory") → runtime base is
|
||||||
|
alpine:3.23, same as upstream's own image, with bash / jq / openssl /
|
||||||
|
postgresql16-client apk-installed for start.sh (the mirror image of the
|
||||||
|
Rathole glibc trap)
|
||||||
|
- **Config is a file, not env**: the app takes one JSON config (`-c`),
|
||||||
|
validated with required `role_mapping` and `policy.path`. start.sh
|
||||||
|
builds it with `jq -n --arg` on first run so secrets are escaped
|
||||||
|
safely into JSON, then admins edit `/app/data/config.json` (targets,
|
||||||
|
role mapping) and `/app/data/opa/simple.rego` (query policy) with the
|
||||||
|
Cloudron file manager; restart applies
|
||||||
|
- **Migrations**: goose SQL embedded in the binary; `migrate-up` subcommand
|
||||||
|
is run explicitly in start.sh (the app also self-migrates on `run` —
|
||||||
|
belt and suspenders, both idempotent)
|
||||||
|
- **Frontend is pre-embedded**: upstream commits `internal/facade/ui/dist`
|
||||||
|
(`go:embed`), so the Go build ships the web UI — no Node stage needed
|
||||||
|
- **Validate() quirks**: targets list may be empty (seed `[]`), but every
|
||||||
|
`tables[].table` must be schema-qualified (`public.foo`) and every
|
||||||
|
role_mapping value must be exactly `admin` or `user`
|
||||||
|
|
||||||
|
**Build Process**:
|
||||||
|
- Upstream `kazhuravlev/database-gateway` v0.24.0 (GPL-3.0, Go 1.26.1)
|
||||||
|
built from the cloned repo (multi-stage pattern #2): golang:1.26-alpine
|
||||||
|
builder mirrors the upstream Dockerfile (CGO_ENABLED=1 + ldflags
|
||||||
|
version stamp) → alpine:3.23 runtime
|
||||||
|
- Logo: upstream `frontend/src/favicon-96x96.png` copied directly
|
||||||
|
- start.sh: psql wait loop on the postgresql addon → seed `.cookie_secret`
|
||||||
|
(openssl rand -hex 32), `opa/simple.rego` (admins-only default),
|
||||||
|
`config.json` (jq template) → `migrate-up` → `exec run`
|
||||||
|
|
||||||
|
**Validation**:
|
||||||
|
- `docker build --cgroup-parent ukrrs-batch.slice -t
|
||||||
|
database-gateway-cloudron:test` → green
|
||||||
|
- `--version` smoke in the image → `gateway version v0.24.0`
|
||||||
|
- End-to-end vs a throwaway postgres:16-alpine on a docker network with
|
||||||
|
fake CLOUDRON_* env: PG wait loop, config + policy seeding, all 5
|
||||||
|
goose migrations applied (bookmarks / query_results tables verified
|
||||||
|
with psql), rego policy compiled, gateway reached the OIDC discovery
|
||||||
|
step and failed only on the bogus issuer (expected off-Cloudron; the
|
||||||
|
real platform issuer resolves at install time)
|
||||||
|
|
||||||
|
**Files Created**:
|
||||||
|
- Dockerfile (multi-stage Go, CGO, alpine:3.23 runtime)
|
||||||
|
- CloudronManifest.json (manifestVersion 2, httpPort 8080, localstorage +
|
||||||
|
postgresql 16)
|
||||||
|
- start.sh (DB wait, jq config seed, policy seed, migrate-up, exec) —
|
||||||
|
committed executable
|
||||||
|
- README.md (auth story, config guide, target walkthrough)
|
||||||
|
- CHANGELOG.md
|
||||||
|
- .env.example (Cloudron-provided env documented)
|
||||||
|
- logo.png (96x96, upstream favicon)
|
||||||
|
|
||||||
|
**Commit**: `feat: add Database-Gateway Cloudron package (Infrastructure) [#639]`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Packaging Pattern: Download Pre-Compiled Binaries
|
## Packaging Pattern: Download Pre-Compiled Binaries
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Environment knobs for the Database Gateway Cloudron package.
|
||||||
|
#
|
||||||
|
# The app itself is configured through /app/data/config.json (seeded on
|
||||||
|
# first start; see README.md). The variables below are consumed by
|
||||||
|
# start.sh at seed time and are provided automatically by Cloudron —
|
||||||
|
# do NOT set them by hand.
|
||||||
|
|
||||||
|
# --- Cloudron platform OIDC provider (injected by Cloudron) -------------------
|
||||||
|
# Written into users.* of /app/data/config.json on first start.
|
||||||
|
#CLOUDRON_OIDC_ISSUER=https://my.example.com/openid
|
||||||
|
#CLOUDRON_OIDC_CLIENT_ID=
|
||||||
|
#CLOUDRON_OIDC_CLIENT_SECRET=
|
||||||
|
#CLOUDRON_OIDC_TOKEN_SIGNATURE_ALGORITHM=RS256
|
||||||
|
|
||||||
|
# --- App origin (injected by Cloudron) ----------------------------------------
|
||||||
|
# Redirect URL is derived as ${CLOUDRON_APP_ORIGIN}/auth/callback.
|
||||||
|
#CLOUDRON_APP_ORIGIN=https://dbgw.example.com
|
||||||
|
|
||||||
|
# --- PostgreSQL addon (injected by Cloudron) ----------------------------------
|
||||||
|
# Gateway storage: profiles, bookmarks, query results, migrations.
|
||||||
|
#CLOUDRON_POSTGRESQL_HOST=
|
||||||
|
#CLOUDRON_POSTGRESQL_PORT=5432
|
||||||
|
#CLOUDRON_POSTGRESQL_DATABASE=
|
||||||
|
#CLOUDRON_POSTGRESQL_USERNAME=
|
||||||
|
#CLOUDRON_POSTGRESQL_PASSWORD=
|
||||||
|
|
||||||
|
# --- Operator-editable files in /app/data -------------------------------------
|
||||||
|
# config.json database targets + role mapping (restart after edit)
|
||||||
|
# opa/simple.rego query authorization policy (restart after edit)
|
||||||
|
# .cookie_secret session cookie secret (rotate = logout everyone)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [0.24.0] - 2026-09-01
|
||||||
|
|
||||||
|
Initial Cloudron package for
|
||||||
|
[Database Gateway](https://github.com/kazhuravlev/database-gateway) v0.24.0
|
||||||
|
(ticket [#639](https://projects.knownelement.com/issues/639)).
|
||||||
|
|
||||||
|
- Multi-stage Go build (golang:1.26-alpine → cloudron/base:3.2.0), frontend
|
||||||
|
embedded by upstream via `go:embed`.
|
||||||
|
- Native OIDC login wired to the Cloudron platform identity provider
|
||||||
|
(`CLOUDRON_OIDC_ISSUER` / `CLIENT_ID` / `CLIENT_SECRET`); roles mapped from
|
||||||
|
the `groups` claim (`admins` → admin, `users` → user).
|
||||||
|
- `postgresql` addon (16) for the gateway's own storage; migrations applied
|
||||||
|
on every start via `migrate-up`.
|
||||||
|
- `/app/data/config.json` + `/app/data/opa/simple.rego` seeded on first run;
|
||||||
|
operators add database targets and OPA policy rules via the file manager.
|
||||||
|
- Single HTTP listener on port 8080 (`httpPort`).
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"manifestVersion": 2,
|
||||||
|
"type": "app",
|
||||||
|
"id": "io.cloudron.dbgateway",
|
||||||
|
"title": "Database Gateway",
|
||||||
|
"description": "Web gateway for secure, policy-controlled access to PostgreSQL databases. Users authenticate via OIDC (Cloudron single sign-on) and run queries that are parsed and authorized by embedded OPA policies per user, target, operation and table. Query results are stored with shareable links for debugging and auditing.",
|
||||||
|
"author": "Kirill Zhuravlev",
|
||||||
|
"website": "https://github.com/kazhuravlev/database-gateway",
|
||||||
|
"contactEmail": "cloudron@tsys.dev",
|
||||||
|
"tagline": "Policy-checked SQL gateway for your databases",
|
||||||
|
"version": "0.24.0",
|
||||||
|
"healthCheckPath": "/",
|
||||||
|
"httpPort": 8080,
|
||||||
|
"memoryLimit": 512,
|
||||||
|
"addons": {
|
||||||
|
"localstorage": true,
|
||||||
|
"postgresql": {
|
||||||
|
"version": "16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mediaLinks": [],
|
||||||
|
"changelog": "Initial Cloudron package for Database Gateway 0.24.0. Native OIDC login wired to the Cloudron platform identity provider (admins group -> gateway admin, users group -> gateway user); local PostgreSQL addon stores profiles, bookmarks and query results; OPA policies and database targets are configured from /app/data. Single HTTP listener on port 8080.",
|
||||||
|
"icon": "file://logo.png"
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# Database Gateway Cloudron Package
|
||||||
|
#
|
||||||
|
# Database Gateway (dbgw) is a web gateway for secure, policy-controlled
|
||||||
|
# access to PostgreSQL databases: users log in via OIDC and every query is
|
||||||
|
# parsed and authorized by embedded OPA policies (per user, target,
|
||||||
|
# operation and table) before it reaches a remote database. Query results
|
||||||
|
# are stored in a local PostgreSQL storage with shareable links.
|
||||||
|
#
|
||||||
|
# Upstream: https://github.com/kazhuravlev/database-gateway (v0.24.0, Go 1.26, Echo)
|
||||||
|
# - Single Go binary; the frontend is already built and embedded in the
|
||||||
|
# repo (internal/facade/ui/dist via go:embed), so no Node stage needed
|
||||||
|
# - Listens on 0.0.0.0:8080; config file passed with `-c config.json`
|
||||||
|
# - Storage schema applied via the `migrate-up` subcommand (embedded SQL)
|
||||||
|
#
|
||||||
|
# Authentication: NATIVE OIDC (preferred). start.sh wires the Cloudron
|
||||||
|
# platform OIDC provider (CLOUDRON_OIDC_ISSUER / CLIENT_ID / CLIENT_SECRET)
|
||||||
|
# into /app/data/config.json on first run; roles map from the Cloudron
|
||||||
|
# `groups` claim (admins -> admin, users -> user).
|
||||||
|
#
|
||||||
|
# NOTE on base images: the SQL parser is a cgo binding (libpg_query), so the
|
||||||
|
# binary MUST be built with CGO_ENABLED=1 — a static CGO_ENABLED=0 build
|
||||||
|
# fails with `undefined: pg.Parse`. A musl-linked binary then needs a musl
|
||||||
|
# runtime, hence alpine:3.23 (same as upstream's own image) instead of the
|
||||||
|
# usual cloudron/base (Ubuntu/glibc).
|
||||||
|
FROM golang:1.26-alpine AS builder
|
||||||
|
|
||||||
|
ARG VERSION=v0.24.0
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# Mirrors the upstream Dockerfile build dependencies (git for module
|
||||||
|
# fetches, gcc/musl-dev for the CGO-enabled build).
|
||||||
|
RUN apk add --no-cache ca-certificates git gcc musl-dev
|
||||||
|
|
||||||
|
# Cache dependency downloads separately from source changes.
|
||||||
|
COPY repo/go.mod repo/go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY repo/ .
|
||||||
|
RUN CGO_ENABLED=1 go build \
|
||||||
|
-ldflags "-s -w -X github.com/dev-services42/version.version=${VERSION}" \
|
||||||
|
-o /out/database-gateway \
|
||||||
|
./cmd/gateway
|
||||||
|
|
||||||
|
# Same runtime base as the upstream image. The tools back start.sh:
|
||||||
|
# bash (script), postgresql16-client (wait for the Cloudron PG addon),
|
||||||
|
# jq (seed config.json), openssl (cookie secret).
|
||||||
|
FROM alpine:3.23
|
||||||
|
|
||||||
|
RUN apk add --no-cache bash ca-certificates jq openssl postgresql16-client
|
||||||
|
|
||||||
|
COPY --from=builder /out/database-gateway /usr/local/bin/database-gateway
|
||||||
|
|
||||||
|
# start.sh waits for the postgresql addon, seeds /app/data/config.json and
|
||||||
|
# /app/data/opa/ on first run, applies migrations, then execs the gateway.
|
||||||
|
# Made executable on the host, not at build time (Cloudron builds hit
|
||||||
|
# permission errors on RUN chmod).
|
||||||
|
COPY start.sh /app/start.sh
|
||||||
|
|
||||||
|
ENV WORKDIR=/app/data
|
||||||
|
WORKDIR ${WORKDIR}
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["/bin/bash", "/app/start.sh"]
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# Database Gateway — Cloudron Package
|
||||||
|
|
||||||
|
[Database Gateway](https://github.com/kazhuravlev/database-gateway) (dbgw) is
|
||||||
|
a web gateway for secure, controlled access to PostgreSQL databases: users
|
||||||
|
log in via OIDC and run SQL through a unified web UI, with every query
|
||||||
|
parsed and authorized by embedded **OPA policies** (per user, target,
|
||||||
|
operation and table). Results are stored in a local PostgreSQL with
|
||||||
|
shareable links for debugging and auditing.
|
||||||
|
|
||||||
|
## Packaging overview
|
||||||
|
|
||||||
|
| Aspect | Choice |
|
||||||
|
|--------|--------|
|
||||||
|
| Pattern | Multi-stage Go build (JOURNAL pattern #2) |
|
||||||
|
| Builder | `golang:1.26-alpine` (upstream's own build recipe, CGO on) |
|
||||||
|
| Base image | `alpine:3.23` (musl runtime required — see below) |
|
||||||
|
| Upstream | v0.24.0 (Go 1.26.1, Echo; frontend pre-built and embedded via `go:embed`) |
|
||||||
|
| Addons | `localstorage` + `postgresql` (16) — storage for profiles, bookmarks, query results |
|
||||||
|
| Auth | **Native OIDC (preferred)** wired to the Cloudron platform identity provider |
|
||||||
|
| Runtime | `start.sh` waits for Postgres, seeds config + OPA policy, `migrate-up`, execs `run` |
|
||||||
|
|
||||||
|
Why alpine instead of `cloudron/base`: the SQL parser is a cgo binding
|
||||||
|
(libpg_query) — the binary must be built with `CGO_ENABLED=1` (a static
|
||||||
|
build fails with `undefined: pg.Parse`) and therefore links musl, which
|
||||||
|
does not exec on Ubuntu/glibc bases. Alpine runtime matches upstream's own
|
||||||
|
image; bash/psql/jq/openssl are apk-installed for `start.sh`.
|
||||||
|
|
||||||
|
Why not the official image: upstream publishes `ghcr.io/kazhuravlev/
|
||||||
|
database-gateway:latest` but tagging is `:latest`-only; building v0.24.0
|
||||||
|
from the cloned source pins the version and lets the ldflags carry the
|
||||||
|
release tag into `/healthcheck`-style version output.
|
||||||
|
|
||||||
|
## Authentication (auth gate verdict: OIDC, preferred)
|
||||||
|
|
||||||
|
Database Gateway authenticates **only** via OIDC — no local user database,
|
||||||
|
no LDAP. This is the preferred row of the auth matrix:
|
||||||
|
|
||||||
|
- `CLOUDRON_OIDC_ISSUER`, `CLOUDRON_OIDC_CLIENT_ID`,
|
||||||
|
`CLOUDRON_OIDC_CLIENT_SECRET` (injected by Cloudron's platform OIDC
|
||||||
|
provider, manifestVersion 2) are written into `/app/data/config.json` on
|
||||||
|
first start.
|
||||||
|
- Redirect URL: `${CLOUDRON_APP_ORIGIN}/auth/callback`.
|
||||||
|
- Scopes: `openid profile email groups`; `role_claim` is `groups`, mapped
|
||||||
|
`admins` → `admin`, `users` → `user` (Cloudron's built-in groups).
|
||||||
|
- Access policy is then enforced per query by OPA (see below), not just at
|
||||||
|
login.
|
||||||
|
|
||||||
|
## Ports
|
||||||
|
|
||||||
|
| Port | Type | Purpose |
|
||||||
|
|------|------|---------|
|
||||||
|
| 8080 | `httpPort` | Web UI + LRPC API (only listener) |
|
||||||
|
|
||||||
|
## Configuration (persistent, in `/app/data`)
|
||||||
|
|
||||||
|
- `config.json` — seeded once on first start (OIDC + storage from Cloudron
|
||||||
|
env). **Add your database targets here** with the Cloudron file manager;
|
||||||
|
restart the app after editing. See
|
||||||
|
[upstream example](https://github.com/kazhuravlev/database-gateway/blob/master/example/config.json)
|
||||||
|
for the full target format (connection, `default_schema`,
|
||||||
|
`tables[].table` must be schema-qualified, `fields` allowlist).
|
||||||
|
- `opa/simple.rego` — seeded default: Cloudron `admins` see all targets and
|
||||||
|
may run any op; everyone else denied until an operator extends the policy
|
||||||
|
(input subjects contain `user:<email>` and `role:<role>`).
|
||||||
|
- `.cookie_secret` — random 32-byte hex, generated once; rotating it
|
||||||
|
invalidates sessions.
|
||||||
|
|
||||||
|
The **postgresql addon** database is the gateway's own storage (users,
|
||||||
|
bookmarks, cached results) — not a query target. Targets point at the
|
||||||
|
*other* PostgreSQL instances you want to reach.
|
||||||
|
|
||||||
|
## Build & test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build --cgroup-parent ukrrs-batch.slice -t database-gateway-cloudron:test Package-Workspace/Infrastructure/database-gateway/
|
||||||
|
docker run --rm --entrypoint /usr/local/bin/database-gateway database-gateway-cloudron:test --version
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `Dockerfile` — multi-stage Go build (golang:1.26-alpine → alpine:3.23, musl)
|
||||||
|
- `CloudronManifest.json` — manifestVersion 2, httpPort 8080, localstorage + postgresql addons
|
||||||
|
- `start.sh` — DB wait, config/policy seeding, migrations, exec gateway
|
||||||
|
- `.env.example` — environment knobs consumed at seed time
|
||||||
|
- `logo.png` — from upstream `frontend/src/favicon-96x96.png`
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
+120
@@ -0,0 +1,120 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Database Gateway runtime setup:
|
||||||
|
# 1. wait for the Cloudron postgresql addon (storage for profiles/bookmarks/
|
||||||
|
# query results)
|
||||||
|
# 2. seed /app/data/config.json + /app/data/opa/ on first run
|
||||||
|
# 3. apply the embedded schema migrations (migrate-up)
|
||||||
|
# 4. exec the gateway (web UI + LRPC API on 0.0.0.0:8080)
|
||||||
|
|
||||||
|
CONFIG_PATH="/app/data/config.json"
|
||||||
|
OPA_DIR="/app/data/opa"
|
||||||
|
COOKIE_SECRET_PATH="/app/data/.cookie_secret"
|
||||||
|
|
||||||
|
# --- 1. wait for PostgreSQL -------------------------------------------------
|
||||||
|
DB_HOST=${CLOUDRON_POSTGRESQL_HOST:-127.0.0.1}
|
||||||
|
DB_PORT=${CLOUDRON_POSTGRESQL_PORT:-5432}
|
||||||
|
DB_NAME=${CLOUDRON_POSTGRESQL_DATABASE:-dbgw}
|
||||||
|
DB_USER=${CLOUDRON_POSTGRESQL_USERNAME:-dbgw}
|
||||||
|
DB_PASSWORD=${CLOUDRON_POSTGRESQL_PASSWORD}
|
||||||
|
|
||||||
|
echo "Waiting for PostgreSQL at ${DB_HOST}:${DB_PORT} ..."
|
||||||
|
until PGPASSWORD="${DB_PASSWORD}" psql -h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" -d "${DB_NAME}" -c '\q' >/dev/null 2>&1; do
|
||||||
|
echo "PostgreSQL is unavailable - sleeping"
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "PostgreSQL is up"
|
||||||
|
|
||||||
|
# --- 2. seed persistent configuration ---------------------------------------
|
||||||
|
# Persistent cookie secret (rotating it would invalidate live sessions).
|
||||||
|
if [[ ! -f "${COOKIE_SECRET_PATH}" ]]; then
|
||||||
|
umask 077
|
||||||
|
openssl rand -hex 32 > "${COOKIE_SECRET_PATH}"
|
||||||
|
echo "Generated new cookie secret"
|
||||||
|
fi
|
||||||
|
COOKIE_SECRET=$(cat "${COOKIE_SECRET_PATH}")
|
||||||
|
|
||||||
|
# Default OPA policy: Cloudron "admins" see every target and may run any op;
|
||||||
|
# everyone else is denied until an operator extends the policy. Edit with the
|
||||||
|
# Cloudron file manager; changes apply on restart.
|
||||||
|
mkdir -p "${OPA_DIR}"
|
||||||
|
if [[ ! -f "${OPA_DIR}/simple.rego" ]]; then
|
||||||
|
cat > "${OPA_DIR}/simple.rego" <<'EOF'
|
||||||
|
package gateway
|
||||||
|
|
||||||
|
# Default Cloudron policy: the admins group is unrestricted; everyone else
|
||||||
|
# is denied until an operator edits this file (input.subjects contains
|
||||||
|
# user:<email> and role:<role> principals).
|
||||||
|
default allow_target := false
|
||||||
|
default allow_query := false
|
||||||
|
|
||||||
|
allow_target if {
|
||||||
|
"role:admin" in input.subjects
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_query if {
|
||||||
|
"role:admin" in input.subjects
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
echo "Seeded default OPA policy at ${OPA_DIR}/simple.rego"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Seed the app config once (jq handles escaping of secrets into JSON). OIDC
|
||||||
|
# comes from the Cloudron platform identity provider; targets (the databases
|
||||||
|
# this gateway may reach) are added by the operator by editing
|
||||||
|
# ${CONFIG_PATH} with the Cloudron file manager.
|
||||||
|
if [[ ! -f "${CONFIG_PATH}" ]]; then
|
||||||
|
jq -n \
|
||||||
|
--arg db_host "${DB_HOST}" \
|
||||||
|
--arg db_name "${DB_NAME}" \
|
||||||
|
--arg db_user "${DB_USER}" \
|
||||||
|
--arg db_password "${DB_PASSWORD}" \
|
||||||
|
--argjson db_port "${DB_PORT}" \
|
||||||
|
--arg issuer "${CLOUDRON_OIDC_ISSUER}" \
|
||||||
|
--arg client_id "${CLOUDRON_OIDC_CLIENT_ID}" \
|
||||||
|
--arg client_secret "${CLOUDRON_OIDC_CLIENT_SECRET}" \
|
||||||
|
--arg origin "${CLOUDRON_APP_ORIGIN}" \
|
||||||
|
--arg cookie_secret "${COOKIE_SECRET}" \
|
||||||
|
--arg opa_dir "${OPA_DIR}" \
|
||||||
|
'{
|
||||||
|
targets: [],
|
||||||
|
users: {
|
||||||
|
client_id: $client_id,
|
||||||
|
client_secret: $client_secret,
|
||||||
|
issuer_url: $issuer,
|
||||||
|
redirect_url: ($origin + "/auth/callback"),
|
||||||
|
scopes: ["openid", "profile", "email", "groups"],
|
||||||
|
role_claim: "groups",
|
||||||
|
role_mapping: {
|
||||||
|
admins: "admin",
|
||||||
|
users: "user"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
policy: { path: $opa_dir },
|
||||||
|
facade: {
|
||||||
|
port: 8080,
|
||||||
|
cookie_secret: $cookie_secret,
|
||||||
|
unsafe_cors_allow_all: false
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
host: $db_host,
|
||||||
|
port: $db_port,
|
||||||
|
database: $db_name,
|
||||||
|
username: $db_user,
|
||||||
|
password: $db_password,
|
||||||
|
use_ssl: false,
|
||||||
|
max_pool_size: 16
|
||||||
|
}
|
||||||
|
}' > "${CONFIG_PATH}"
|
||||||
|
chmod 600 "${CONFIG_PATH}"
|
||||||
|
echo "Seeded config at ${CONFIG_PATH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 3. migrations -----------------------------------------------------------
|
||||||
|
echo "Applying database migrations ..."
|
||||||
|
/usr/local/bin/database-gateway -c "${CONFIG_PATH}" migrate-up
|
||||||
|
|
||||||
|
# --- 4. run --------------------------------------------------------------------
|
||||||
|
echo "Starting Database Gateway on :8080 ..."
|
||||||
|
exec /usr/local/bin/database-gateway -c "${CONFIG_PATH}" run
|
||||||
@@ -9,9 +9,9 @@ The Cloudron component focuses on packaging upstream free/libre/open application
|
|||||||
### 📊 Current Progress
|
### 📊 Current Progress
|
||||||
|
|
||||||
- **Total Applications**: ~57 (see [GitUrlList.txt](GitUrlList.txt))
|
- **Total Applications**: ~57 (see [GitUrlList.txt](GitUrlList.txt))
|
||||||
- **Completed Packages**: 11/~57 (~19%)
|
- **Completed Packages**: 12/~57 (~21%)
|
||||||
- **Packaging Templates**: Created ✅
|
- **Packaging Templates**: Created ✅
|
||||||
- **Packages Committed & Pushed**: 11 ✅
|
- **Packages Committed & Pushed**: 12 ✅
|
||||||
- **Build Tickets**: 46 filed (#633-#678, umbrella
|
- **Build Tickets**: 46 filed (#633-#678, umbrella
|
||||||
[#632](https://projects.knownelement.com/issues/632), Redmine project 55);
|
[#632](https://projects.knownelement.com/issues/632), Redmine project 55);
|
||||||
grist-core excluded (packaged upstream)
|
grist-core excluded (packaged upstream)
|
||||||
@@ -33,6 +33,7 @@ The Cloudron component focuses on packaging upstream free/libre/open application
|
|||||||
| 9 | Windmill | Automation | ~2GB | 8000 | localstorage, postgresql | ✅ Committed |
|
| 9 | Windmill | Automation | ~2GB | 8000 | localstorage, postgresql | ✅ Committed |
|
||||||
| 10 | Easy-Gate | Infrastructure | 3.18GB | 8080 | localstorage (auth proxy) | ✅ Committed |
|
| 10 | Easy-Gate | Infrastructure | 3.18GB | 8080 | localstorage (auth proxy) | ✅ Committed |
|
||||||
| 11 | Rathole | Infrastructure | 3.51GB | 8000, 2333, 5200-5299 | localstorage (auth proxy) | ✅ Committed |
|
| 11 | Rathole | Infrastructure | 3.51GB | 8000, 2333, 5200-5299 | localstorage (auth proxy) | ✅ Committed |
|
||||||
|
| 12 | Database Gateway | Infrastructure | 93.7MB | 8080 | localstorage, postgresql | ✅ Committed |
|
||||||
|
|
||||||
### 📦 Packages in Development
|
### 📦 Packages in Development
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ None currently in development.
|
|||||||
|
|
||||||
### ⚡ Productivity Metrics
|
### ⚡ Productivity Metrics
|
||||||
|
|
||||||
- **Packages Completed**: 11/~57 (~19%)
|
- **Packages Completed**: 12/~57 (~21%)
|
||||||
- **Average Package Time**: ~30 minutes
|
- **Average Package Time**: ~30 minutes
|
||||||
- **Success Rate**: 100% (all packages built successfully)
|
- **Success Rate**: 100% (all packages built successfully)
|
||||||
- **Commits Pushed**: 100% (all packages pushed to remote)
|
- **Commits Pushed**: 100% (all packages pushed to remote)
|
||||||
@@ -91,7 +92,7 @@ Applications are organized by function rather than programming language:
|
|||||||
| **Documentation-Tools** | Documentation and diagramming tools | 3 | 1/3 (33%) |
|
| **Documentation-Tools** | Documentation and diagramming tools | 3 | 1/3 (33%) |
|
||||||
| **Financial-Payments** | Payment processing and financial infrastructure | 1 | 0/1 (0%) |
|
| **Financial-Payments** | Payment processing and financial infrastructure | 1 | 0/1 (0%) |
|
||||||
| **Financial-Trading** | Trading and financial algorithm platforms | 1 | 0/1 (0%) |
|
| **Financial-Trading** | Trading and financial algorithm platforms | 1 | 0/1 (0%) |
|
||||||
| **Infrastructure** | Infrastructure and networking tools | 6 | 2/6 (33%) |
|
| **Infrastructure** | Infrastructure and networking tools | 6 | 3/6 (50%) |
|
||||||
| **Legal** | Legal and compliance applications | 1 | 0/1 (0%) |
|
| **Legal** | Legal and compliance applications | 1 | 0/1 (0%) |
|
||||||
| **Low-Code** | Low-code and no-code platforms | 3 | 1/3 (33%) |
|
| **Low-Code** | Low-code and no-code platforms | 3 | 1/3 (33%) |
|
||||||
| **Monitoring** | Monitoring and observability tools | 6 | 1/6 (17%) |
|
| **Monitoring** | Monitoring and observability tools | 6 | 1/6 (17%) |
|
||||||
@@ -113,7 +114,7 @@ Applications are organized by function rather than programming language:
|
|||||||
| [DataHub](https://github.com/datahub-project/datahub) | [GitHub](https://github.com/datahub-project/datahub) | Modern data stack for end-to-end data management | Data-Management |
|
| [DataHub](https://github.com/datahub-project/datahub) | [GitHub](https://github.com/datahub-project/datahub) | Modern data stack for end-to-end data management | Data-Management |
|
||||||
| [Docassemble](https://github.com/jhpyle/docassemble) | [GitHub](https://github.com/jhpyle/docassemble) | Open-source expert system for guided interviews | Legal |
|
| [Docassemble](https://github.com/jhpyle/docassemble) | [GitHub](https://github.com/jhpyle/docassemble) | Open-source expert system for guided interviews | Legal |
|
||||||
| [Pimcore](https://github.com/pimcore/pimcore) | [GitHub](https://github.com/pimcore/pimcore) | Open-source digital experience platform | Business-Apps |
|
| [Pimcore](https://github.com/pimcore/pimcore) | [GitHub](https://github.com/pimcore/pimcore) | Open-source digital experience platform | Business-Apps |
|
||||||
| [Database-Gateway](https://github.com/kazhuravlev/database-gateway) | [GitHub](https://github.com/kazhuravlev/database-gateway) | Database gateway and connection management | Infrastructure |
|
| [Database-Gateway](https://github.com/kazhuravlev/database-gateway) | [GitHub](https://github.com/kazhuravlev/database-gateway) | Database gateway and connection management | Infrastructure | ✅ Packaged |
|
||||||
| [Webhook](https://github.com/adnanh/webhook) | [GitHub](https://github.com/adnanh/webhook) | Lightweight webhook receiver | API-Gateway | ✅ Packaged |
|
| [Webhook](https://github.com/adnanh/webhook) | [GitHub](https://github.com/adnanh/webhook) | Lightweight webhook receiver | API-Gateway | ✅ Packaged |
|
||||||
| [FX](https://github.com/metrue/fx) | [GitHub](https://github.com/metrue/fx) | Function as a Service platform | DevOps-Tools |
|
| [FX](https://github.com/metrue/fx) | [GitHub](https://github.com/metrue/fx) | Function as a Service platform | DevOps-Tools |
|
||||||
| [Fonoster](https://github.com/fonoster/fonoster) | [GitHub](https://github.com/fonoster/fonoster) | Open-source CPaaS for communications | Communication |
|
| [Fonoster](https://github.com/fonoster/fonoster) | [GitHub](https://github.com/fonoster/fonoster) | Open-source CPaaS for communications | Communication |
|
||||||
|
|||||||
@@ -3,20 +3,20 @@
|
|||||||
> **Human read-only. Agents maintain this file automatically after each work
|
> **Human read-only. Agents maintain this file automatically after each work
|
||||||
> session.** Do not edit by hand — the next agent run will overwrite it.
|
> session.** Do not edit by hand — the next agent run will overwrite it.
|
||||||
>
|
>
|
||||||
> **Last updated:** 2026-09-01 by Crush (GLM-5.2) — Rathole packaged
|
> **Last updated:** 2026-09-01 by Crush (GLM-5.2) — Database Gateway
|
||||||
> (#650, Infrastructure, 11th package); auth gate verdict: no user concept,
|
> packaged (#639, Infrastructure, 12th package); auth gate verdict: native
|
||||||
> status page behind the Cloudron auth proxy, tunnels token-authenticated.
|
> OIDC (preferred) — platform provider wired via CLOUDRON_OIDC_* env.
|
||||||
|
|
||||||
## Current State: STABLE (packaging phase, ongoing)
|
## Current State: STABLE (packaging phase, ongoing)
|
||||||
|
|
||||||
Cloudron packaging pipeline is operational. 11 of ~57 upstream applications are
|
Cloudron packaging pipeline is operational. 12 of ~57 upstream applications are
|
||||||
packaged, committed, and pushed. Packaging templates exist for the core
|
packaged, committed, and pushed. Packaging templates exist for the core
|
||||||
patterns. The gardening protocol (this file + AGENTS.md) keeps docs in sync.
|
patterns. The gardening protocol (this file + AGENTS.md) keeps docs in sync.
|
||||||
All remaining apps now carry build tickets (#633-#678) under umbrella
|
All remaining apps now carry build tickets (#633-#678) under umbrella
|
||||||
[#632](https://projects.knownelement.com/issues/632) in Redmine project 55 —
|
[#632](https://projects.knownelement.com/issues/632) in Redmine project 55 —
|
||||||
ready for the sequential grind-driver pattern.
|
ready for the sequential grind-driver pattern.
|
||||||
|
|
||||||
## Completed Packages (11)
|
## Completed Packages (12)
|
||||||
|
|
||||||
| # | Application | Category | Pattern | Port(s) | Addons |
|
| # | Application | Category | Pattern | Port(s) | Addons |
|
||||||
|---|-------------|----------|---------|---------|--------|
|
|---|-------------|----------|---------|---------|--------|
|
||||||
@@ -31,6 +31,7 @@ ready for the sequential grind-driver pattern.
|
|||||||
| 9 | Windmill | Automation | Official-image wrapper + start.sh | 8000 | localstorage, postgresql |
|
| 9 | Windmill | Automation | Official-image wrapper + start.sh | 8000 | localstorage, postgresql |
|
||||||
| 10 | Easy-Gate | Infrastructure | Multi-stage (Go) + auth proxy | 8080 | localstorage |
|
| 10 | Easy-Gate | Infrastructure | Multi-stage (Go) + auth proxy | 8080 | localstorage |
|
||||||
| 11 | Rathole | Infrastructure | Pre-compiled binaries + auth proxy | 8000, 2333, 5200-5299 | localstorage |
|
| 11 | Rathole | Infrastructure | Pre-compiled binaries + auth proxy | 8000, 2333, 5200-5299 | localstorage |
|
||||||
|
| 12 | Database Gateway | Infrastructure | Multi-stage (Go, CGO) | 8080 | localstorage, postgresql |
|
||||||
|
|
||||||
Each package lives in `Package-Workspace/<Category>/<app>/` and contains a
|
Each package lives in `Package-Workspace/<Category>/<app>/` and contains a
|
||||||
`Dockerfile`, `CloudronManifest.json`, `README.md`, `CHANGELOG.md`, `logo.png`,
|
`Dockerfile`, `CloudronManifest.json`, `README.md`, `CHANGELOG.md`, `logo.png`,
|
||||||
@@ -119,7 +120,7 @@ Full write-ups of each pattern + challenges are in [`JOURNAL.md`](JOURNAL.md).
|
|||||||
| DevOps-Tools | 1 | 0/1 | |
|
| DevOps-Tools | 1 | 0/1 | |
|
||||||
| Financial-Payments | 1 | 0/1 | |
|
| Financial-Payments | 1 | 0/1 | |
|
||||||
| Financial-Trading | 1 | 0/1 | |
|
| Financial-Trading | 1 | 0/1 | |
|
||||||
| Infrastructure | 6 | 2/6 | easy-gate, rathole done |
|
| Infrastructure | 6 | 3/6 | easy-gate, rathole, database-gateway done |
|
||||||
| Legal | 1 | 0/1 | |
|
| Legal | 1 | 0/1 | |
|
||||||
| Project-Management | 1 | 0/1 | |
|
| Project-Management | 1 | 0/1 | |
|
||||||
| Scientific-Computing | 2 | 0/2 | |
|
| Scientific-Computing | 2 | 0/2 | |
|
||||||
@@ -133,7 +134,7 @@ Auth capability is a hard gate before packaging (see
|
|||||||
LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
||||||
(unacceptable / blocked-on-auth).
|
(unacceptable / blocked-on-auth).
|
||||||
|
|
||||||
### Completed packages (11)
|
### Completed packages (12)
|
||||||
|
|
||||||
| App | OIDC | LDAP | Verdict | Note |
|
| App | OIDC | LDAP | Verdict | Note |
|
||||||
|-----|------|------|---------|------|
|
|-----|------|------|---------|------|
|
||||||
@@ -148,6 +149,7 @@ LDAP acceptable (risk flag), 🔄 = auth-proxy (no users), ❌ = local-only
|
|||||||
| Windmill | yes | no | ✅ preferred | **Packaged**; OIDC configured via Admin Settings UI (no env vars) |
|
| Windmill | yes | no | ✅ preferred | **Packaged**; OIDC configured via Admin Settings UI (no env vars) |
|
||||||
| Easy-Gate | n/a | n/a | 🔄 proxy | **Packaged** with `httpAuth.type=proxy` (no user concept; IP-subnet groups only) |
|
| Easy-Gate | n/a | n/a | 🔄 proxy | **Packaged** with `httpAuth.type=proxy` (no user concept; IP-subnet groups only) |
|
||||||
| Rathole | n/a | n/a | 🔄 proxy | **Packaged** with `httpAuth.type=proxy` on the status page; tunnels secured by mandatory per-service tokens (Noise/TLS optional) |
|
| Rathole | n/a | n/a | 🔄 proxy | **Packaged** with `httpAuth.type=proxy` on the status page; tunnels secured by mandatory per-service tokens (Noise/TLS optional) |
|
||||||
|
| Database Gateway | yes | no | ✅ preferred | **Packaged**; native OIDC-only app — platform provider env (`CLOUDRON_OIDC_*`) seeded into config.json; roles from the `groups` claim |
|
||||||
|
|
||||||
### Candidates researched
|
### Candidates researched
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user