194 lines
6.0 KiB
JavaScript
194 lines
6.0 KiB
JavaScript
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, /不创建报价、订单、付款单、积分、钱包、余额/);
|
|
});
|