ops: align production ETL with legacy admin source

This commit is contained in:
Jesse_Chen
2026-08-09 13:53:07 +08:00
parent 664d8adbf0
commit d36ca7aac2
3 changed files with 31 additions and 6 deletions
@@ -392,10 +392,9 @@ async function readSourceUsers(source, sourceAuthSchema, activeAdminUserIds) {
);
}
async function readActiveAdminUserIds(source, sourceTables) {
if (!sourceTables.has("admin_users")) {
throw new SafeProductionMigrationError("source public.admin_users is missing");
}
export async function readActiveAdminUserIds(source, sourceTables, ownerUserId) {
// Legacy production used a single ADMIN_EMAILS allowlist and has no admin tables.
if (!sourceTables.has("admin_users")) return new Set([ownerUserId]);
const result = await source.query(
"select user_id from public.admin_users where revoked_at is null order by user_id",
);
@@ -442,6 +441,7 @@ async function assertNoUnmappedSourceTables(source, sourceTables, targetTables)
}
async function assertActiveAdminRoles(source, sourceTables, ownerUserId) {
if (!sourceTables.has("admin_users")) return;
if (!sourceTables.has("admin_user_roles") || !sourceTables.has("admin_roles")) {
const result = await source.query(
`select count(*)::bigint as count from public.admin_users where revoked_at is null and user_id <> $1`,
@@ -715,7 +715,7 @@ async function preflightContext(source, target, config, { requireEmpty = true }
readSchema(source, "auth"),
readSchema(target, "public"),
]);
const activeAdminUserIds = await readActiveAdminUserIds(source, sourcePublic);
const activeAdminUserIds = await readActiveAdminUserIds(source, sourcePublic, config.ownerUserId);
const users = await readSourceUsers(source, sourceAuth, activeAdminUserIds);
assertActiveAdminUsers(users, activeAdminUserIds, config.ownerUserId);
if (requireEmpty) await assertTargetEmpty(target, targetPublic);
@@ -10,6 +10,7 @@ import {
normalizeAuthUser,
normalizeAuthUsers,
parseMode,
readActiveAdminUserIds,
readConfiguration,
readSchema,
rowsSha256,
@@ -126,6 +127,20 @@ test("production identity preflight rejects duplicate canonical emails", () => {
);
});
test("legacy production without admin tables promotes only the designated Owner", async () => {
const ownerId = "018f4e6d-7a11-7000-8000-000000000001";
const source = {
async query() {
throw new Error("legacy fallback must not query a missing admin_users table");
},
};
assert.deepEqual(
[...await readActiveAdminUserIds(source, new Map(), ownerId)],
[ownerId],
);
});
test("active administrators become usable identity admins", () => {
const ownerId = "018f4e6d-7a11-7000-8000-000000000001";
const adminId = "018f4e6d-7a11-7000-8000-000000000002";