Files
Jyotisha/frontend/tests/high-risk-billing-routes-contract.test.ts
Jesse_Chen c30b4b906b
Staging Backend Quality Gate / validate (push) Successful in 14m3s
Staging Backend Quality Gate / publish (push) Successful in 21m16s
fix(admin): remove model reauthentication
2026-08-07 23:23:00 +08:00

112 lines
7.1 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
const source = (path: string) => readFileSync(new URL(`../${path}`, import.meta.url), "utf8");
const packagesRoute = source("src/app/api/payment/packages/route.ts");
const createRoute = source("src/app/api/payment/epay/create/route.ts");
const statusRoute = source("src/app/api/payment/epay/status/route.ts");
const notifyRoute = source("src/app/api/payment/epay/notify/route.ts");
const productsRoute = source("src/app/api/admin/products/route.ts");
const epaySettingsRoute = source("src/app/api/admin/epay-settings/route.ts");
const subscriptionsRoute = source("src/app/api/admin/subscriptions/route.ts");
const featureFlagsRoute = source("src/app/api/admin/feature-flags/route.ts");
const modelsRoute = source("src/app/api/admin/models/route.ts");
const modelDiscoveryRoute = source("src/app/api/admin/models/discover/route.ts");
const modelMutationHandler = source("src/lib/admin/model-mutation-handler.ts");
const ordersRoute = source("src/app/api/admin/orders/route.ts");
const codesRoute = source("src/app/api/admin/codes/route.ts");
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");
test("billing.subscriptions only gates new trial and subscription purchases", () => {
assert.match(packagesRoute, /loadRuntimeFeatureFlags\(\["billing\.subscriptions"\]\)/);
assert.match(packagesRoute, /subscriptionsEnabled \|\| product\.product_type === "credit_pack"/);
assert.match(createRoute, /product\.product_type !== "credit_pack"[\s\S]*billing\.subscriptions[\s\S]*BILLING_SUBSCRIPTIONS_DISABLED/);
assert.ok(
createRoute.indexOf("BILLING_SUBSCRIPTIONS_DISABLED") < createRoute.indexOf('.from("payment_orders").insert'),
"the flag must reject subscription orders before insertion",
);
});
test("existing payment orders remain queryable and settleable when subscriptions are disabled", () => {
assert.doesNotMatch(statusRoute, /billing\.subscriptions|loadRuntimeFeatureFlags/);
assert.doesNotMatch(notifyRoute, /billing\.subscriptions|loadRuntimeFeatureFlags/);
assert.match(statusRoute, /from\("payment_orders"\)/);
assert.match(notifyRoute, /createEpayNotifyHandler[\s\S]*settle_order/);
});
test("billing and operations high-risk writes use the shared mutation guard", () => {
assert.match(productsRoute, /requireHighRiskAdminMutation\(request, permission\)/);
assert.match(productsRoute, /body\.data\.reason[\s\S]*requestId/);
assert.match(epaySettingsRoute, /requireHighRiskAdminMutation\(request, "billing\.adjustments\.write"\)/);
assert.match(epaySettingsRoute, /admin_save_epay_settings/);
assert.match(subscriptionsRoute, /requireHighRiskAdminMutation\(request,"billing\.adjustments\.write"\)/);
assert.match(subscriptionsRoute, /body\.data\.reason,rid/);
assert.match(featureFlagsRoute, /action==="publish"\?await requireHighRiskAdminMutation\(request,"ops\.flags\.write"\):await requireAdminMutation/);
assert.match(featureFlagsRoute, /admin_publish_feature_flag[\s\S]*b\.data\.reason,rid/);
});
test("model provider changes and release mutations use the ordinary admin guard", () => {
assert.match(modelsRoute, /await requireAdminMutation\(request, permission\)/);
assert.doesNotMatch(modelsRoute, /requireHighRiskAdminMutation/);
assert.match(modelDiscoveryRoute, /requireAdminMutation\(request,"models\.test"\)/);
assert.doesNotMatch(modelDiscoveryRoute, /requireHighRiskAdminMutation/);
assert.match(modelsRoute, /handleAdminModelMutation\(/);
assert.match(modelMutationHandler, /admin_save_model_provider/);
assert.match(modelMutationHandler, /admin_publish_model/);
assert.match(modelMutationHandler, /probeAndRecord[\s\S]*admin_rollback_model/);
});
test("self-hosted payment catalog uses simple queries and immutable product snapshots", () => {
assert.doesNotMatch(packagesRoute, /product_entitlements\s*\(/);
assert.doesNotMatch(createRoute, /product_entitlements\s*\(/);
assert.match(packagesRoute, /\.from\("billing_products"\)[\s\S]*\.from\("product_entitlements"\)/);
assert.match(packagesRoute, /entitlementsByProduct/);
assert.match(createRoute, /\.from\("billing_products"\)[\s\S]*\.from\("product_entitlements"\)/);
assert.match(createRoute, /oneTimePerUser:\s*product\.one_time_per_user/);
assert.match(createRoute, /product_snapshot:\s*productSnapshot/);
});
test("order adjustments require reauth, reason, version, idempotency request id, and the domain RPC", () => {
assert.match(
ordersRoute,
/requireHighRiskAdminMutation\(\s*request,\s*"billing\.adjustments\.write",?\s*\)/,
);
assert.match(ordersRoute, /expectedVersion:\s*z\.number\(\)\.int\(\)\.min\(0\)/);
assert.match(ordersRoute, /reason:\s*z\.string\(\)\.trim\(\)\.min\(1\)\.max\(500\)/);
assert.match(ordersRoute, /queryAdminRows<AdjustmentRow>/);
assert.match(ordersRoute, /public\.admin_adjust_order\(/);
assert.match(ordersRoute, /requestId\(request\)/);
assert.doesNotMatch(ordersRoute, /createAdminSupabaseClient|\.rpc\(/);
assert.match(billingOperationsUi, /retry_grant/);
assert.match(billingOperationsUi, /compensate/);
assert.match(billingOperationsUi, /record_refund/);
assert.match(billingOperationsUi, /reauthPermission="billing\.adjustments\.write"/);
assert.match(billingOperationsUi, /不调用支付网关|仅记录账务/);
});
test("every redemption-code write requires a reason and forwards it to the audited RPC", () => {
assert.match(codesRoute, /requireHighRiskAdminMutation\(\s*request,\s*"billing\.adjustments\.write",?\s*\)/);
assert.equal((codeRoute.match(/requireHighRiskAdminMutation\(/g) ?? []).length, 2);
assert.match(codesRoute, /reason:\s*z\.string\(\)\.trim\(\)\.min\(1\)\.max\(500\)/);
assert.match(codesRoute, /p_reason:\s*parsed\.data\.reason/);
assert.match(codeRoute, /const revokeCodeSchema[\s\S]*reason:\s*z\.string\(\)\.trim\(\)\.min\(1\)\.max\(500\)/);
assert.match(codeRoute, /const updateCodeSchema[\s\S]*reason:\s*z\.string\(\)\.trim\(\)\.min\(1\)\.max\(500\)/);
assert.match(codeRoute, /p_reason:\s*body\.reason/);
assert.match(codeRoute, /p_reason:\s*parsedBody\.data\.reason/);
assert.match(codesHelper, /queryAdminRows<RpcCodeRow>/);
assert.match(codesHelper, /public\.admin_create_redemption_codes\(/);
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.equal((codesUi.match(/reauthPermission="billing\.adjustments\.write"/g) ?? []).length, 3);
assert.match(codesUi, /open=\{Boolean\(pendingCreate\)\}[\s\S]*onSubmit=\{submitCreate\}/);
assert.match(codesUi, /open=\{Boolean\(pendingEdit\)\}[\s\S]*onSubmit=\{submitEdit\}/);
assert.match(codesUi, /<ReasonActionModal[\s\S]*onSubmit=\{\(reason\) => revoke\(revokeRecord!, reason\)\}/);
});