Files
cairnobs/metadata/migrate.sh
T
jcoffey-dev 3eb0f4c589 Phase 4: SSO scaffolding, RBAC enforcement, tenant-scoped dashboards, audit logging, K8s deployment
RBAC (api/internal/authz) is live on /query and /dashboards, backed by a
new enterprise/ module (session issuance, audit logging, RBAC storage,
OIDC/SAML protocol wiring) that core never imports -- only calls over
HTTP. Found and fixed a real cross-tenant vulnerability in dashboards
(no tenant_id filtering at all) while writing the threat model doc.

Two things are explicitly NOT done, documented rather than hidden:
tenant isolation for log data itself (/query still shares one ClickHouse
connection and Tantivy index across every tenant -- RBAC controls who
can query, not what a query can see), and human SSO login (protocol
wiring exists, no HTTP handler calls it yet). See
docs/security/threat-model.md and docs/phase-4-runbook.md.

Also adds deploy/ (Go Operator + Helm chart, validated offline only --
no cluster was reachable in this environment).
2026-08-13 22:16:59 -07:00

50 lines
2.0 KiB
Bash

#!/usr/bin/env bash
# Applies migrations/*.sql to Postgres in filename order, tracking what's
# already been applied in a schema_migrations table -- same shape as
# /storage/migrate.sh, adapted for psql instead of curl since Postgres
# supports real transactions per file (kept to one DDL object per file
# anyway, for repo-wide consistency of what a migration "version" means).
set -euo pipefail
POSTGRES_HOST="${POSTGRES_HOST:-localhost}"
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
POSTGRES_USER="${POSTGRES_USER:-sentry}"
POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-}"
POSTGRES_DATABASE="${POSTGRES_DATABASE:-sentry_metadata}"
# Password for the restricted audit-log-writer Postgres role (Phase 4
# task 4, see /docs/phase-4-isolation-design.md's audit logging
# section) -- a second, narrower-granted role, not the shared
# POSTGRES_PASSWORD above. Passed to psql via -v so the migration SQL
# file can reference it as :'audit_writer_password' without ever
# hardcoding a credential in a file checked into git.
AUDIT_WRITER_PASSWORD="${AUDIT_WRITER_PASSWORD:-audit-writer-dev-only}"
export PGPASSWORD="$POSTGRES_PASSWORD"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MIGRATIONS_DIR="${SCRIPT_DIR}/migrations"
psql_exec() {
psql -v ON_ERROR_STOP=1 -X -q -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" \
-v audit_writer_password="$AUDIT_WRITER_PASSWORD" "$@"
}
echo "Ensuring schema_migrations table exists..."
psql_exec -c "CREATE TABLE IF NOT EXISTS schema_migrations (version TEXT PRIMARY KEY, applied_at TIMESTAMPTZ NOT NULL DEFAULT now())"
applied="$(psql_exec -t -A -c "SELECT version FROM schema_migrations")"
shopt -s nullglob
for file in "${MIGRATIONS_DIR}"/*.sql; do
version="$(basename "$file")"
if grep -qx "$version" <<< "$applied"; then
echo "skip ${version} (already applied)"
continue
fi
echo "apply ${version}"
psql_exec -f "$file"
psql_exec -c "INSERT INTO schema_migrations (version) VALUES ('${version}')"
done
echo "Migrations complete."