Skip to content

Commit 85ed898

Browse files
committed
chore: update database permissions and verification scripts
- Added instructions in `DB-MIGRATIONS.md` to run `rebootstrap-roles` after `drop-everything`. - Enhanced `0001_create_app_db_users.sh` and `0002_setup_management_database.sh` to conditionally grant schema USAGE privileges. - Updated `rebootstrap-full-bootstrap.sh` to include conditional grants for schema USAGE. - Modified `verify-bootstrap-contract.sh` to check for schema USAGE privileges and added verification for querying `linear_migration_history`.
1 parent 10c2065 commit 85ed898

5 files changed

Lines changed: 60 additions & 6 deletions

File tree

docs/development/DB-MIGRATIONS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Rules:
3030
- Prefix must be four digits.
3131
- Filename format must be `^[0-9]{4}_[a-z0-9_]+\.sql$`.
3232
- Previously applied files are immutable.
33+
- After **drop-everything**, run **rebootstrap-roles** before migrate jobs. Rebootstrap must grant **`USAGE ON SCHEMA public`** to read/read_write roles **as the DB owner** (migrator cannot delegate schema USAGE on Postgres 15+ after `DROP SCHEMA public`; see Podverse-aligned bootstrap scripts).
3334

3435
## Validate
3536

infra/k8s/base/db/source/bootstrap/0001_create_app_db_users.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,22 @@ END
4747
4848
GRANT CONNECT ON DATABASE ${DB_APP_NAME} TO ${DB_APP_MIGRATOR_USER}, ${DB_APP_READ_WRITE_USER}, ${DB_APP_READ_USER};
4949
GRANT USAGE, CREATE ON SCHEMA public TO ${DB_APP_MIGRATOR_USER};
50+
-- OWNER must grant schema USAGE (MIGRATOR cannot delegate USAGE without WITH GRANT OPTION; recreated public after DROP SCHEMA has no PUBLIC grant).
51+
GRANT USAGE ON SCHEMA public TO ${DB_APP_READ_WRITE_USER}, ${DB_APP_READ_USER};
5052
SQL
5153

5254
psql -v ON_ERROR_STOP=1 --username "$DB_APP_MIGRATOR_USER" -d "$DB_APP_NAME" <<SQL
53-
GRANT USAGE ON SCHEMA public TO ${DB_APP_READ_WRITE_USER}, ${DB_APP_READ_USER};
55+
DO \$\$
56+
BEGIN
57+
IF NOT has_schema_privilege('${DB_APP_READ_WRITE_USER}', 'public', 'USAGE') THEN
58+
EXECUTE format('GRANT USAGE ON SCHEMA public TO %I', '${DB_APP_READ_WRITE_USER}');
59+
END IF;
60+
61+
IF NOT has_schema_privilege('${DB_APP_READ_USER}', 'public', 'USAGE') THEN
62+
EXECUTE format('GRANT USAGE ON SCHEMA public TO %I', '${DB_APP_READ_USER}');
63+
END IF;
64+
END
65+
\$\$;
5466
5567
GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE ON ALL TABLES IN SCHEMA public TO ${DB_APP_READ_WRITE_USER};
5668
GRANT SELECT, USAGE, UPDATE ON ALL SEQUENCES IN SCHEMA public TO ${DB_APP_READ_WRITE_USER};

infra/k8s/base/db/source/bootstrap/0002_setup_management_database.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ psql -v ON_ERROR_STOP=1 --username "$DB_APP_OWNER_USER" --dbname "$DB_APP_NAME"
6666
psql -v ON_ERROR_STOP=1 --username "$DB_MANAGEMENT_OWNER_USER" --dbname "$MANAGEMENT_DB_NAME" <<SQL
6767
GRANT CONNECT ON DATABASE ${MANAGEMENT_DB_NAME} TO ${DB_MANAGEMENT_MIGRATOR_USER}, ${DB_MANAGEMENT_READ_WRITE_USER}, ${DB_MANAGEMENT_READ_USER};
6868
GRANT USAGE, CREATE ON SCHEMA public TO ${DB_MANAGEMENT_MIGRATOR_USER};
69+
-- Same rationale as 0001 app owner block (public recreated without PUBLIC USAGE; OWNER must grant).
70+
GRANT USAGE ON SCHEMA public TO ${DB_MANAGEMENT_READ_WRITE_USER}, ${DB_MANAGEMENT_READ_USER};
6971
SQL
7072

7173
psql -v ON_ERROR_STOP=1 --username "$DB_MANAGEMENT_MIGRATOR_USER" --dbname "$MANAGEMENT_DB_NAME" <<SQL

infra/k8s/base/ops/source/database/runner/rebootstrap-full-bootstrap.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,22 @@ END
7070
7171
GRANT CONNECT ON DATABASE ${DB_APP_NAME} TO ${DB_APP_MIGRATOR_USER}, ${DB_APP_READ_WRITE_USER}, ${DB_APP_READ_USER};
7272
GRANT USAGE, CREATE ON SCHEMA public TO ${DB_APP_MIGRATOR_USER};
73+
GRANT USAGE ON SCHEMA public TO ${DB_APP_READ_WRITE_USER}, ${DB_APP_READ_USER};
7374
SQL
7475

7576
export PGPASSWORD="${DB_APP_MIGRATOR_PASSWORD}"
7677
psql -v ON_ERROR_STOP=1 --username "${DB_APP_MIGRATOR_USER}" --dbname "${DB_APP_NAME}" <<SQL
77-
GRANT USAGE ON SCHEMA public TO ${DB_APP_READ_WRITE_USER}, ${DB_APP_READ_USER};
78+
DO \$\$
79+
BEGIN
80+
IF NOT has_schema_privilege('${DB_APP_READ_WRITE_USER}', 'public', 'USAGE') THEN
81+
EXECUTE format('GRANT USAGE ON SCHEMA public TO %I', '${DB_APP_READ_WRITE_USER}');
82+
END IF;
83+
84+
IF NOT has_schema_privilege('${DB_APP_READ_USER}', 'public', 'USAGE') THEN
85+
EXECUTE format('GRANT USAGE ON SCHEMA public TO %I', '${DB_APP_READ_USER}');
86+
END IF;
87+
END
88+
\$\$;
7889
7990
GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE ON ALL TABLES IN SCHEMA public TO ${DB_APP_READ_WRITE_USER};
8091
GRANT SELECT, USAGE, UPDATE ON ALL SEQUENCES IN SCHEMA public TO ${DB_APP_READ_WRITE_USER};
@@ -143,6 +154,7 @@ export PGPASSWORD="${DB_MANAGEMENT_OWNER_PASSWORD}"
143154
psql -v ON_ERROR_STOP=1 --username "${DB_MANAGEMENT_OWNER_USER}" --dbname "${DB_MANAGEMENT_NAME}" <<SQL
144155
GRANT CONNECT ON DATABASE ${DB_MANAGEMENT_NAME} TO ${DB_MANAGEMENT_MIGRATOR_USER}, ${DB_MANAGEMENT_READ_WRITE_USER}, ${DB_MANAGEMENT_READ_USER};
145156
GRANT USAGE, CREATE ON SCHEMA public TO ${DB_MANAGEMENT_MIGRATOR_USER};
157+
GRANT USAGE ON SCHEMA public TO ${DB_MANAGEMENT_READ_WRITE_USER}, ${DB_MANAGEMENT_READ_USER};
146158
SQL
147159

148160
export PGPASSWORD="${DB_MANAGEMENT_MIGRATOR_PASSWORD}"

infra/k8s/base/ops/source/database/runner/verify-bootstrap-contract.sh

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
# - uuid-ossp extension exists
55
# - linear_migration_history table exists
66
# - public schema has tables
7-
# - read_write/read roles have expected table privileges
7+
# - read_write/read roles have schema USAGE and expected table privileges
8+
# - read_write/read can query linear_migration_history (runtime access, not catalog-only)
89

910
set -euo pipefail
1011

@@ -17,13 +18,15 @@ DB_PORT="${DB_PORT:-${METABOOST_DB_SERVICE_PORT:-5432}}"
1718
: "${DB_APP_READ_WRITE_USER:?Missing DB_APP_READ_WRITE_USER}"
1819
: "${DB_APP_READ_WRITE_PASSWORD:?Missing DB_APP_READ_WRITE_PASSWORD}"
1920
: "${DB_APP_READ_USER:?Missing DB_APP_READ_USER}"
21+
: "${DB_APP_READ_PASSWORD:?Missing DB_APP_READ_PASSWORD}"
2022

2123
: "${DB_MANAGEMENT_OWNER_USER:?Missing DB_MANAGEMENT_OWNER_USER}"
2224
: "${DB_MANAGEMENT_OWNER_PASSWORD:?Missing DB_MANAGEMENT_OWNER_PASSWORD}"
2325
: "${DB_MANAGEMENT_NAME:?Missing DB_MANAGEMENT_NAME}"
2426
: "${DB_MANAGEMENT_READ_WRITE_USER:?Missing DB_MANAGEMENT_READ_WRITE_USER}"
2527
: "${DB_MANAGEMENT_READ_WRITE_PASSWORD:?Missing DB_MANAGEMENT_READ_WRITE_PASSWORD}"
2628
: "${DB_MANAGEMENT_READ_USER:?Missing DB_MANAGEMENT_READ_USER}"
29+
: "${DB_MANAGEMENT_READ_PASSWORD:?Missing DB_MANAGEMENT_READ_PASSWORD}"
2730

2831
run_query() {
2932
local password="$1"
@@ -63,8 +66,10 @@ check_database_contract() {
6366
local role_user="$2"
6467
local db_name="$3"
6568
local read_write_role="$4"
66-
local read_role="$5"
67-
local label="$6"
69+
local read_write_password="$5"
70+
local read_role="$6"
71+
local read_password="$7"
72+
local label="$8"
6873

6974
echo "Verifying ${label} database bootstrap contract (${db_name})..."
7075

@@ -80,6 +85,12 @@ check_database_contract() {
8085
table_count="$(run_query "$role_password" "$role_user" "$db_name" "SELECT count(*) FROM pg_catalog.pg_tables WHERE schemaname = 'public';")"
8186
assert_positive_int "${label}: public schema table count" "$table_count"
8287

88+
local rw_schema_usage ro_schema_usage
89+
rw_schema_usage="$(run_query "$role_password" "$role_user" "$db_name" "SELECT has_schema_privilege('${read_write_role}', 'public', 'USAGE');")"
90+
ro_schema_usage="$(run_query "$role_password" "$role_user" "$db_name" "SELECT has_schema_privilege('${read_role}', 'public', 'USAGE');")"
91+
assert_equals "${label}: read_write schema USAGE" "$rw_schema_usage" "t"
92+
assert_equals "${label}: read schema USAGE" "$ro_schema_usage" "t"
93+
8394
local rw_select rw_insert rw_update rw_delete ro_select
8495
rw_select="$(run_query "$role_password" "$role_user" "$db_name" "SELECT has_table_privilege('${read_write_role}', 'public.linear_migration_history', 'SELECT');")"
8596
rw_insert="$(run_query "$role_password" "$role_user" "$db_name" "SELECT has_table_privilege('${read_write_role}', 'public.linear_migration_history', 'INSERT');")"
@@ -92,22 +103,38 @@ check_database_contract() {
92103
assert_equals "${label}: read_write UPDATE" "$rw_update" "t"
93104
assert_equals "${label}: read_write DELETE" "$rw_delete" "t"
94105
assert_equals "${label}: read SELECT" "$ro_select" "t"
106+
107+
local rw_history_count ro_history_count
108+
rw_history_count="$(run_query "$read_write_password" "$read_write_role" "$db_name" "SELECT count(*) FROM linear_migration_history;")"
109+
ro_history_count="$(run_query "$read_password" "$read_role" "$db_name" "SELECT count(*) FROM linear_migration_history;")"
110+
assert_positive_int "${label}: read_write linear_migration_history row count" "$rw_history_count"
111+
assert_positive_int "${label}: read linear_migration_history row count" "$ro_history_count"
112+
113+
if [[ "$label" == "management" ]]; then
114+
local can_query_management_user
115+
can_query_management_user="$(run_query "$read_write_password" "$read_write_role" "$db_name" "SELECT EXISTS (SELECT 1 FROM management_user LIMIT 1);")"
116+
assert_equals "${label}: read_write can query management_user" "$can_query_management_user" "t"
117+
fi
95118
}
96119

97120
check_database_contract \
98121
"$DB_APP_OWNER_PASSWORD" \
99122
"$DB_APP_OWNER_USER" \
100123
"$DB_APP_NAME" \
101124
"$DB_APP_READ_WRITE_USER" \
125+
"$DB_APP_READ_WRITE_PASSWORD" \
102126
"$DB_APP_READ_USER" \
127+
"$DB_APP_READ_PASSWORD" \
103128
"app"
104129

105130
check_database_contract \
106131
"$DB_MANAGEMENT_OWNER_PASSWORD" \
107132
"$DB_MANAGEMENT_OWNER_USER" \
108133
"$DB_MANAGEMENT_NAME" \
109134
"$DB_MANAGEMENT_READ_WRITE_USER" \
135+
"$DB_MANAGEMENT_READ_WRITE_PASSWORD" \
110136
"$DB_MANAGEMENT_READ_USER" \
137+
"$DB_MANAGEMENT_READ_PASSWORD" \
111138
"management"
112139

113-
echo "Bootstrap contract verification passed for app and management databases."
140+
echo "Bootstrap contract verification passed for app and management databases."

0 commit comments

Comments
 (0)