diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-backup-scaling.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-backup-scaling.tsx
index a52017cdb0..ed012253fb 100644
--- a/apps/gittensory-ui/src/routes/docs.self-hosting-backup-scaling.tsx
+++ b/apps/gittensory-ui/src/routes/docs.self-hosting-backup-scaling.tsx
@@ -96,8 +96,9 @@ QDRANT_URL=http://qdrant:6333`}
@pgbouncer:5432/gittensory
+npm run selfhost:postgres:migrate -- --sqlite /data/gittensory.sqlite
+npm run selfhost:postgres:migrate -- --sqlite /data/gittensory.sqlite --execute`}
/>
Restore checks
diff --git a/scripts/export-grafana-reporting-db.sh b/scripts/export-grafana-reporting-db.sh
index 52cbd0c809..7d0ced17b6 100644
--- a/scripts/export-grafana-reporting-db.sh
+++ b/scripts/export-grafana-reporting-db.sh
@@ -41,7 +41,7 @@ pg_enabled() {
}
pg_scalar() {
- psql "$PG_DB" -X -q -t -A -v ON_ERROR_STOP=1 -c "$1"
+ PGDATABASE="$PG_DB" psql -X -q -t -A -v ON_ERROR_STOP=1 -c "$1"
}
pg_table_exists() {
@@ -63,7 +63,7 @@ pg_column_exists() {
pg_copy_csv() {
query="$1"
out="$2"
- psql "$PG_DB" -X -q -v ON_ERROR_STOP=1 -c "COPY ($query) TO STDOUT WITH CSV" >"$out"
+ PGDATABASE="$PG_DB" psql -X -q -v ON_ERROR_STOP=1 -c "COPY ($query) TO STDOUT WITH CSV" >"$out"
}
sqlite_import_csv() {
diff --git a/scripts/migrate-selfhost-sqlite-to-postgres.ts b/scripts/migrate-selfhost-sqlite-to-postgres.ts
index 13a400fc59..8e4653f8d2 100644
--- a/scripts/migrate-selfhost-sqlite-to-postgres.ts
+++ b/scripts/migrate-selfhost-sqlite-to-postgres.ts
@@ -36,14 +36,15 @@ const TABLES_ALLOWED_AFTER_SCHEMA_INIT = new Set(["global_agent_controls", "glob
const POSTGRES_TEXT_NUL_REPLACEMENT = "\uFFFD";
function usage(): string {
- return `Usage: npm run selfhost:postgres:migrate -- --sqlite --postgres-url [--execute]
+ return `Usage: DATABASE_URL= npm run selfhost:postgres:migrate -- --sqlite [--execute]
Copies a self-host SQLite database into an empty Postgres backend. The default is a transactionally
-rolled-back dry run. Pass --execute to commit the copy.
+rolled-back dry run. Pass --execute to commit the copy. Prefer DATABASE_URL over --postgres-url so
+the Postgres credential is not exposed through process command lines.
Options:
--sqlite SQLite source file. Defaults to DATABASE_PATH or /data/gittensory.sqlite.
- --postgres-url Postgres target URL. Defaults to DATABASE_URL.
+ --postgres-url Postgres target URL. Defaults to DATABASE_URL; avoid this on shared hosts.
--migrations-dir Migration directory. Defaults to migrations.
--execute Commit the copy. Omit for a rollback dry run.
--allow-non-empty Allow non-empty target tables only when overlapping primary keys are identical.
diff --git a/test/unit/selfhost-grafana-reporting.test.ts b/test/unit/selfhost-grafana-reporting.test.ts
index a0289c582b..96298d3695 100644
--- a/test/unit/selfhost-grafana-reporting.test.ts
+++ b/test/unit/selfhost-grafana-reporting.test.ts
@@ -50,6 +50,16 @@ function fakePsql(root: string): string {
psql,
`#!/bin/sh
args="$*"
+case " $args " in
+ *" postgres://"*|*" postgresql://"*)
+ echo 'psql command line leaked postgres URL' >&2
+ exit 8
+ ;;
+esac
+if [ "\${PGDATABASE:-}" != "postgres://gittensory:pw@postgres:5432/gittensory" ]; then
+ echo 'psql did not receive postgres URL through PGDATABASE' >&2
+ exit 8
+fi
case "$args" in
*\\\\copy*)
echo 'unexpected psql meta-command copy' >&2