import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { DatabaseSync } from "node:sqlite"; import test from "node:test"; import { AUDIT_INVITATION_REVOCATION_SQL, CREATE_INVITATION_REVOCATION_IDEMPOTENCY_SQL, REVOKE_INVITATION_SQL, deriveInvitationDisplayState, } from "../db/invitations.ts"; test("derives active, expired, and revoked invitation states", () => { const now = "2026-08-12T12:00:00.000Z"; assert.equal( deriveInvitationDisplayState( { state: "active", ends_at: "2026-08-13T00:00:00.000Z", revoked_at: null }, now, ), "active", ); assert.equal( deriveInvitationDisplayState( { state: "active", ends_at: now, revoked_at: null }, now, ), "expired", ); assert.equal( deriveInvitationDisplayState( { state: "revoked", ends_at: null, revoked_at: now }, now, ), "revoked", ); }); test("atomically revokes one administrator invitation without duplicate audit", () => { const database = new DatabaseSync(":memory:"); database.exec(` CREATE TABLE entitlement_grants ( id TEXT PRIMARY KEY, source TEXT NOT NULL, state TEXT NOT NULL, revoked_at TEXT ); CREATE TABLE idempotency_records ( scope TEXT NOT NULL, key TEXT NOT NULL, request_hash TEXT NOT NULL, response_json TEXT NOT NULL, status_code INTEGER NOT NULL, expires_at TEXT NOT NULL, created_at TEXT NOT NULL, PRIMARY KEY (scope, key) ); CREATE TABLE audit_events ( id TEXT PRIMARY KEY, actor_id TEXT NOT NULL, action TEXT NOT NULL, target_type TEXT NOT NULL, target_id TEXT NOT NULL, reason TEXT NOT NULL, before_json TEXT, after_json TEXT, correlation_id TEXT NOT NULL, created_at TEXT NOT NULL ); INSERT INTO entitlement_grants VALUES ('grant_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'admin_exemption', 'active', NULL), ('grant_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'public_beta', 'active', NULL); `); const now = "2026-08-12T12:00:00.000Z"; const scope = "admin:exemption:revoke"; const key = "revoke-key-0001"; const requestHash = "request-hash-1"; const grantId = "grant_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; const beforeJson = JSON.stringify({ id: grantId, state: "active", revoked_at: null }); const afterJson = JSON.stringify({ id: grantId, state: "revoked", revoked_at: now }); database.exec("BEGIN IMMEDIATE"); const first = [ Number(database.prepare(CREATE_INVITATION_REVOCATION_IDEMPOTENCY_SQL).run( scope, key, requestHash, afterJson, "2026-08-13T12:00:00.000Z", now, grantId, ).changes), Number(database.prepare(REVOKE_INVITATION_SQL).run( now, grantId, scope, key, requestHash, ).changes), Number(database.prepare(AUDIT_INVITATION_REVOCATION_SQL).run( "audit_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "admin-user", grantId, "结束该账户闭测", beforeJson, afterJson, "corr_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", now, scope, key, requestHash, ).changes), ]; database.exec("COMMIT"); assert.deepEqual(first, [1, 1, 1]); assert.deepEqual( { ...database.prepare("SELECT state, revoked_at FROM entitlement_grants WHERE id = ?").get(grantId) }, { state: "revoked", revoked_at: now }, ); assert.equal( database.prepare("SELECT COUNT(*) AS count FROM audit_events").get().count, 1, ); const laterKey = "revoke-key-0002"; const laterHash = "request-hash-2"; database.exec("BEGIN IMMEDIATE"); const repeated = [ Number(database.prepare(CREATE_INVITATION_REVOCATION_IDEMPOTENCY_SQL).run( scope, laterKey, laterHash, afterJson, "2026-08-13T12:00:00.000Z", now, grantId, ).changes), Number(database.prepare(REVOKE_INVITATION_SQL).run( now, grantId, scope, laterKey, laterHash, ).changes), Number(database.prepare(AUDIT_INVITATION_REVOCATION_SQL).run( "audit_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "admin-user", grantId, "重复撤销", beforeJson, afterJson, "corr_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", now, scope, laterKey, laterHash, ).changes), ]; database.exec("COMMIT"); assert.deepEqual(repeated, [0, 0, 0]); assert.equal( database.prepare("SELECT COUNT(*) AS count FROM audit_events").get().count, 1, ); assert.equal( database.prepare("SELECT state FROM entitlement_grants WHERE id LIKE 'grant_b%'").get().state, "active", ); database.close(); }); test("keeps invitation administration authenticated, explicit, and non-monetary", async () => { const [route, repository, invitationSql, actions, adminPage, billingPage, contract] = await Promise.all([ readFile(new URL("../app/api/admin/exemptions/route.ts", import.meta.url), "utf8"), readFile(new URL("../db/repository.ts", import.meta.url), "utf8"), readFile(new URL("../db/invitations.ts", import.meta.url), "utf8"), readFile(new URL("../app/admin/AdminActions.tsx", import.meta.url), "utf8"), readFile(new URL("../app/admin/page.tsx", import.meta.url), "utf8"), readFile(new URL("../app/dashboard/billing/page.tsx", import.meta.url), "utf8"), readFile(new URL("../docs/commercial-contract.md", import.meta.url), "utf8"), ]); assert.match(route, /getCloudViewer/); assert.match(route, /viewer\.isAdmin/); assert.match(route, /payload\.action === "revoke"/); assert.match(repository, /admin:exemption:revoke/); assert.match(invitationSql, /entitlement\.invitation_revoked/); assert.match(actions, /停止该账户后续闭测配对资格/); assert.match(actions, /既有主机不会被自动断开/); assert.match(adminPage, /闭测邀请记录/); assert.match(billingPage, /下次资格变化/); assert.match(billingPage, /闭测邀请即将到期/); assert.match(billingPage, /deriveInvitationDisplayState/); assert.match(contract, /不创建报价、订单、付款单、积分、钱包、余额/); });