From d2a7fe3151c2d7523aa799c091a15f532a62bc7c Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 21 Aug 2026 00:27:54 +0200 Subject: [PATCH] fix: keep migration objects on stable role --- deploy/README.md | 4 +++- deploy/tenant-engine-migration.yaml | 2 ++ src/tenant_engine/migrate.py | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 7c9581a..a673465 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -57,7 +57,9 @@ This is an operator cutover, not an application startup step: 1. Scale the live SQLite Deployment to zero and verify no pod holds the PVC. 2. Snapshot or copy the SQLite file without modifying it. 3. Apply `deploy/tenant-engine-migration.yaml` with the new immutable image and - wait for success. + wait for success. The Job sets role to the stable + `tenant_engine_migrate` group before DDL; short-lived OpenBao login roles + must never own schema objects that outlive their lease. 4. Run the transfer under the migration-role URL: ```bash diff --git a/deploy/tenant-engine-migration.yaml b/deploy/tenant-engine-migration.yaml index ebaec00..952c688 100644 --- a/deploy/tenant-engine-migration.yaml +++ b/deploy/tenant-engine-migration.yaml @@ -28,6 +28,8 @@ spec: - tenant-engine-migrate - --url-file - /var/run/secrets/postgres-migration/url + - --role + - tenant_engine_migrate env: - name: TENANT_ENGINE_MIGRATION_DATABASE_URL_FILE value: /var/run/secrets/postgres-migration/url diff --git a/src/tenant_engine/migrate.py b/src/tenant_engine/migrate.py index 1ba1313..6d98eff 100644 --- a/src/tenant_engine/migrate.py +++ b/src/tenant_engine/migrate.py @@ -17,21 +17,31 @@ def main() -> None: default="/app/migrations/postgres/0001_tenant_store.sql", help="SQL migration file", ) + parser.add_argument( + "--role", + default=os.getenv("TENANT_ENGINE_MIGRATION_ROLE", ""), + help="stable group role that must own objects created by a leased login", + ) args = parser.parse_args() if not args.url_file: parser.error("--url-file or TENANT_ENGINE_MIGRATION_DATABASE_URL_FILE is required") try: import psycopg + from psycopg import sql as psycopg_sql except ImportError as exc: # pragma: no cover - deployment guard raise RuntimeError("install tenant-engine[postgres] to run migrations") from exc dsn = Path(args.url_file).read_text(encoding="utf-8").strip() if not dsn: raise RuntimeError("migration database URL file is empty") - sql = Path(args.migration).read_text(encoding="utf-8") + migration_sql = Path(args.migration).read_text(encoding="utf-8") with psycopg.connect(dsn, autocommit=True) as connection: - connection.execute(sql) + if args.role: + connection.execute( + psycopg_sql.SQL("SET ROLE {}").format(psycopg_sql.Identifier(args.role)) + ) + connection.execute(migration_sql) if __name__ == "__main__":