fix(admin): remove redundant confirmations and repair code access
Independent Staging Quality Gate / validate (push) Failing after 12m38s
Independent Staging Quality Gate / publish (push) Has been skipped

This commit is contained in:
Jesse_Chen
2026-08-16 17:55:15 +08:00
parent f12a43ad1d
commit 945d61fa1c
21 changed files with 314 additions and 413 deletions
+2 -5
View File
@@ -25,7 +25,6 @@ const compatibilityRoles = readFileSync(new URL("../../deploy/postgres/002-ensur
const administratorsRoute = readFileSync(new URL("../src/app/api/admin/administrators/route.ts", import.meta.url), "utf8");
const mfaRoute = readFileSync(new URL("../src/app/api/admin/mfa/route.ts", import.meta.url), "utf8");
const mfaSecurity = readFileSync(new URL("../src/components/admin/mfa-security.tsx", import.meta.url), "utf8");
const confirmActionModal = readFileSync(new URL("../src/components/admin/confirm-action-modal.tsx", import.meta.url), "utf8");
const customersRoute = readFileSync(new URL("../src/app/api/admin/customers/route.ts", import.meta.url), "utf8");
const adminUser = readFileSync(new URL("../src/lib/supabase/admin.ts", import.meta.url), "utf8");
const codesRoute = readFileSync(new URL("../src/app/api/admin/codes/route.ts", import.meta.url), "utf8");
@@ -50,7 +49,7 @@ test("admin APIs use persisted Better Auth roles with admin-only boundaries", ()
assert.doesNotMatch(auth, /ADMIN_EMAILS|isAdminEmail/);
assert.match(authBoundary, /readAuthProvider\(\)\?\.trim\(\) !== "self-hosted"/);
assert.match(authBoundary, /后台服务暂时不可用", 503/);
assert.match(codesRoute, /requireAdminMutation\(\s*request,\s*"billing\.adjustments\.write",?\s*\)/);
assert.match(codesRoute, /requireAdminMutation\(\s*request,\s*"admin\.access",?\s*\)/);
assert.equal((codeRoute.match(/requireAdminMutation\(/g) ?? []).length, 2);
assert.doesNotMatch(codesRoute, /requireHighRiskAdminMutation/);
assert.doesNotMatch(codeRoute, /requireHighRiskAdminMutation/);
@@ -237,9 +236,7 @@ test("administrator writes keep permission and origin checks without operation-l
assert.doesNotMatch(adminHttp, /requireHighRiskAdminMutation|verifyHighRiskAdminProof/);
assert.doesNotMatch(administratorsRoute, /requireHighRiskAdminMutation/);
assert.equal(existsSync(new URL("../src/app/api/admin/reauth/route.ts", import.meta.url)), false);
assert.doesNotMatch(confirmActionModal, /操作原因|name="reason"|TextArea/);
assert.match(confirmActionModal, /await onConfirm\(\)/);
assert.doesNotMatch(confirmActionModal, /邮箱验证码|\/api\/admin\/reauth|reauthPermission/);
assert.equal(existsSync(new URL("../src/components/admin/confirm-action-modal.tsx", import.meta.url)), false);
assert.match(authFactory, /twoFactor\(/);
assert.match(authFactory, /schema: identityModelMapping\.twoFactor/);
+3 -6
View File
@@ -1,5 +1,5 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { existsSync, readFileSync } from "node:fs";
import test from "node:test";
import {
@@ -75,13 +75,10 @@ test("MFA API keeps native Better Auth enrollment, recovery, rotation, and proof
assert.match(migration, /grant select, insert, update, delete on table identity\.two_factors[\s\S]*identity_runtime/);
});
test("business confirmation UI has no per-operation input while account MFA remains separate", () => {
const modal = readFileSync(new URL("../src/components/admin/confirm-action-modal.tsx", import.meta.url), "utf8");
test("business operation confirmation UI is removed while account MFA remains separate", () => {
const http = readFileSync(new URL("../src/lib/admin/http.ts", import.meta.url), "utf8");
assert.doesNotMatch(modal, /操作原因|name="reason"|TextArea/);
assert.match(modal, /await onConfirm\(\)/);
assert.doesNotMatch(modal, /邮箱验证码|\/api\/admin\/reauth|reauthPermission/);
assert.equal(existsSync(new URL("../src/components/admin/confirm-action-modal.tsx", import.meta.url)), false);
assert.match(http, /requireAdminMutation/);
assert.doesNotMatch(http, /requireHighRiskAdminMutation|verifyHighRiskAdminProof/);
});
@@ -43,20 +43,19 @@ test("admin mutations retain session, permission, trusted-origin, server audit,
const codesRoute = source("src/app/api/admin/codes/route.ts");
const codesHelper = source("src/lib/admin/codes.ts");
const codesUi = source("src/components/admin/codes-resource.tsx");
const modal = source("src/components/admin/confirm-action-modal.tsx");
assert.equal(existsSync(new URL("src/components/admin/confirm-action-modal.tsx", root)), false);
assert.match(http, /requirePermission\(permission, request\.headers\)/);
assert.match(http, /isTrustedAdminMutationRequest\(request, process\.env\.ADMIN_USER_ORIGIN\)/);
assert.match(codesRoute, /requireAdminMutation\([\s\S]*"billing\.adjustments\.write"/);
assert.match(codesRoute, /requireAdminMutation\([\s\S]*"admin\.access"/);
assert.doesNotMatch(codesRoute, /reason:\s*z\.string/);
assert.match(codesRoute, /p_reason:\s*"admin_console_create_redemption_codes"/);
assert.match(codesHelper, /JSON\.stringify\(input\.p_codes\)/);
assert.match(codesRoute, /requestId\(request\)/);
assert.match(codesRoute, /admin_create_redemption_codes/);
assert.match(codesUi, /permissions\.includes\("billing\.adjustments\.write"\)/);
assert.match(codesUi, /okText="确认生成"/);
assert.doesNotMatch(modal, /操作原因|TextArea|name="reason"/);
assert.match(modal, /await onConfirm\(\)/);
assert.match(codesUi, /permissions\.includes\("admin\.access"\)/);
assert.match(codesUi, /onFinish=\{\(values\) => void submitCreate\(values\)\}/);
assert.doesNotMatch(codesUi, /ConfirmActionModal|pendingCreate|pendingEdit|revokeRecord/);
});
test("account-level TOTP MFA and customer login email OTP remain available", () => {
@@ -33,13 +33,13 @@ const mutationMappings = [
name: "兑换码创建",
ui: "src/components/admin/codes-resource.tsx",
api: "src/app/api/admin/codes/route.ts",
permission: "billing.adjustments.write",
permission: "admin.access",
},
{
name: "兑换码编辑与撤销",
ui: "src/components/admin/codes-resource.tsx",
api: "src/app/api/admin/codes/[id]/route.ts",
permission: "billing.adjustments.write",
permission: "admin.access",
},
{
name: "功能开关发布",
@@ -66,7 +66,7 @@ test("admin mutation UI permissions match ordinary API guards without operation
await t.test(mapping.name, () => {
const ui = source(mapping.ui);
const api = source(mapping.api);
assert.match(ui, /ConfirmActionModal/);
assert.doesNotMatch(ui, /ConfirmActionModal|Popconfirm|Modal\.confirm/);
assert.doesNotMatch(ui, /reauthPermission|邮箱验证码|\/api\/admin\/reauth/);
assert.match(api, new RegExp(String.raw`requireAdminMutation\(\s*request,\s*(?:permission|["']${mapping.permission.replaceAll(".", "\\.")}["']),?\s*\)`));
assert.doesNotMatch(api, /requireHighRiskAdminMutation/);
@@ -75,6 +75,17 @@ test("admin mutation UI permissions match ordinary API guards without operation
}
});
test("redemption-code list and mutations are available to every authenticated admin role", () => {
const providers = source("src/lib/admin/providers.ts");
const route = source("src/app/api/admin/codes/route.ts");
assert.match(
providers,
/codes:\s*\{\s*read:\s*"admin\.access",\s*write:\s*"admin\.access"\s*\}/,
);
assert.match(route, /await requirePermission\("admin\.access"\)/);
});
test("product management localizes product, billing and entitlement enums", () => {
const ui = source("src/components/admin/product-management.tsx");
@@ -115,18 +126,16 @@ test("model management uses ordinary admin mutation guards without reauth", () =
assert.doesNotMatch(ui, /验证并(?:保存|获取)/);
});
test("admin request failures are real Error instances and confirmation modal keeps failures visible", () => {
test("admin request failures are real Error instances and operation confirmation UI is absent", () => {
const providers = source("src/lib/admin/providers.ts");
const modal = source("src/components/admin/confirm-action-modal.tsx");
assert.match(
providers,
/Object\.assign\(new Error\(message\),\s*\{\s*statusCode: response\.status,/,
);
assert.doesNotMatch(providers, /throw \{ message, statusCode/);
assert.match(modal, /catch \(error\)[\s\S]*setActionError\(error instanceof Error \? error\.message/);
assert.doesNotMatch(modal, /操作原因|name="reason"|TextArea/);
assert.match(modal, /await onConfirm\(\)/);
assert.doesNotMatch(modal, /reauth|邮箱验证码|发送验证码/);
for (const path of mutationMappings.map((mapping) => mapping.ui)) {
assert.doesNotMatch(source(path), /ConfirmActionModal|Popconfirm|Modal\.confirm/);
}
});
test("customer list is always masked and a single explicit reveal is audited each time", () => {
@@ -154,7 +163,8 @@ test("administrator UI supports all six roles and exposes last-owner protection"
for (const role of ["owner", "model_admin", "billing_admin", "operations", "support", "auditor"]) {
assert.match(ui, new RegExp(`["']${role}["']`));
}
assert.match(ui, /method: pendingAction\.action === "assign" \? "POST" : "DELETE"/);
assert.match(ui, /method: action\.action === "assign" \? "POST" : "DELETE"/);
assert.doesNotMatch(ui, /pendingAction|ConfirmActionModal/);
const mutationSection = route.slice(route.indexOf("async function mutate"));
assert.match(mutationSection, /last_owner_protected/);
assert.match(mutationSection, /不能撤销最后一位 Owner,请先分配另一位 Owner/);
+1 -1
View File
@@ -22,7 +22,7 @@ test("admin surfaces await database-backed administrator checks", () => {
assert.match(adminSource, /export async function isAdminUser/);
assert.match(adminSource, /admin_has_permission\(\$1, 'admin\.access'\)/);
assert.match(sessionSource, /await requirePermission\("admin\.access"\)/);
assert.match(codesSource, /await requireAdminMutation\(\s*request,\s*"billing\.adjustments\.write",?\s*\)/);
assert.match(codesSource, /await requireAdminMutation\(\s*request,\s*"admin\.access",?\s*\)/);
assert.doesNotMatch(codesSource, /requireHighRiskAdminMutation/);
assert.match(accountSource, /const isAdmin = await isAdminUser\(user\)/);
assert.match(accountSource, /isAdmin,/);
@@ -20,6 +20,8 @@ const codeRoute = source("src/app/api/admin/codes/[id]/route.ts");
const codesHelper = source("src/lib/admin/codes.ts");
const billingOperationsUi = source("src/components/admin/billing-operations-resources.tsx");
const codesUi = source("src/components/admin/codes-resource.tsx");
const redemptionAccessMigration = source("supabase/migrations/20260816010000_admin_redemption_admin_access.sql");
const baseRedemptionMigration = source("supabase/migrations/20260805010000_reconcile_admin_redemption_audit.sql");
test("billing.subscriptions only gates new trial and subscription purchases", () => {
assert.match(packagesRoute, /loadRuntimeFeatureFlags\(\["billing\.subscriptions"\]\)/);
@@ -94,7 +96,8 @@ test("order adjustments require permission, version, server audit reason, reques
});
test("redemption-code writes generate server audit reasons and encode JSONB for self-hosted pg", () => {
assert.match(codesRoute, /requireAdminMutation\(\s*request,\s*"billing\.adjustments\.write",?\s*\)/);
assert.match(codesRoute, /await requirePermission\("admin\.access"\)/);
assert.match(codesRoute, /requireAdminMutation\(\s*request,\s*"admin\.access",?\s*\)/);
assert.equal((codeRoute.match(/requireAdminMutation\(/g) ?? []).length, 2);
assert.doesNotMatch(codeRoute, /requireHighRiskAdminMutation/);
assert.doesNotMatch(codesRoute, /reason:\s*z\.string/);
@@ -108,9 +111,15 @@ test("redemption-code writes generate server audit reasons and encode JSONB for
assert.match(codesHelper, /public\.admin_update_redemption_code\(/);
assert.match(codesHelper, /public\.admin_revoke_redemption_code\(/);
assert.doesNotMatch(codesHelper, /createAdminSupabaseClient|\.rpc\(|\$\{functionName\}/);
assert.match(codesUi, /permissions\.includes\("billing\.adjustments\.write"\)/);
assert.match(codesUi, /permissions\.includes\("admin\.access"\)/);
assert.doesNotMatch(codesUi, /reauthPermission|邮箱验证码|\/api\/admin\/reauth/);
assert.match(codesUi, /open=\{Boolean\(pendingCreate\)\}[\s\S]*onConfirm=\{submitCreate\}/);
assert.match(codesUi, /open=\{Boolean\(pendingEdit\)\}[\s\S]*onConfirm=\{submitEdit\}/);
assert.match(codesUi, /<ConfirmActionModal[\s\S]*onConfirm=\{\(\) => revoke\(revokeRecord!\)\}/);
assert.match(codesUi, /onFinish=\{\(values\) => void submitCreate\(values\)\}/);
assert.match(codesUi, /onFinish=\{\(values\) => void submitEdit\(values\)\}/);
assert.match(codesUi, /onClick=\{\(\) => void revoke\(record\)\}/);
assert.doesNotMatch(codesUi, /ConfirmActionModal|pendingCreate|pendingEdit|revokeRecord/);
assert.equal((redemptionAccessMigration.match(/admin_has_permission\(p_actor_user_id,'admin\.access'\)/g) ?? []).length, 3);
assert.match(redemptionAccessMigration, /new\.permission_used := 'admin\.access'/);
assert.match(baseRedemptionMigration, /admin_verified_actor_email/);
assert.match(redemptionAccessMigration, /grant execute on function public\.admin_create_redemption_codes/);
assert.doesNotMatch(redemptionAccessMigration, /billing\.adjustments\.write/);
});