Local Build and Deploy / deploy (push) Successful in 1m7s
Remove 19 unused source files (no importers anywhere in src/):
- src/actions/admin-permissions.ts, admin-radio.ts, admin-user-edit.ts,
admin-users.ts (functionality lives in @/actions/users and
@/actions/permissions)
- src/components/admin/confirm-action.tsx, page-header.tsx
- src/components/motion-elements.tsx
- src/lib/format-date.ts
- src/lib/catalog-categories/* (incl. re-export barrel)
- src/lib/foundation/{index,database,middleware,validation}.ts (errors/action
kept, still imported directly)
- src/lib/services/imager/{avatar-renderer,memory-cache}.ts
- src/lib/services/nitro-assets.ts
Update admin-operations-contract test to drop the two removed action-file
gates (their permission coverage already exists in users.ts/permissions.ts).
Add knip.json for repeatable dead-code audits.
Verified: tsc --noEmit clean, next build succeeds, full test suite green
(301/301).
121 lines
4.2 KiB
TypeScript
121 lines
4.2 KiB
TypeScript
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
import { join, relative } from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
const ROUTES: Array<[string, string]> = [
|
|
["moderation", "PERMS.MODERATION_VIEW"],
|
|
["moderation/actions", "PERMS.MODERATION_EDIT"],
|
|
["moderation/cfh", "PERMS.MODERATION_VIEW"],
|
|
["logs/audit", "PERMS.LOGS_VIEW"],
|
|
["analytics", "PERMS.ANALYTICS_VIEW"],
|
|
["devops", "PERMS.DEVOPS_VIEW"],
|
|
["online", "PERMS.USERS_VIEW"],
|
|
["commandocentrum", "PERMS.RCON_EXECUTE"],
|
|
["users/edit/[id]", "PERMS.USERS_EDIT"],
|
|
["settings", "PERMS.SETTINGS_VIEW"],
|
|
["theme", "PERMS.SETTINGS_VIEW"],
|
|
["emulator", "PERMS.SETTINGS_VIEW"],
|
|
["bans", "PERMS.BANS_VIEW"],
|
|
["wordfilter", "PERMS.WORDFILTER_VIEW"],
|
|
["articles", "PERMS.NEWS_VIEW"],
|
|
["shop", "PERMS.SHOP_VIEW"],
|
|
["transactions", "PERMS.SHOP_VIEW"],
|
|
["vouchers", "PERMS.SHOP_VIEW"],
|
|
["vpn", "PERMS.SETTINGS_VIEW"],
|
|
["ip", "PERMS.SETTINGS_VIEW"],
|
|
["maintenance", "PERMS.SETTINGS_VIEW"],
|
|
["alerts", "PERMS.NOTIFICATIONS_VIEW"],
|
|
["tags", "PERMS.PAGES_VIEW"],
|
|
["ads", "PERMS.PAGES_VIEW"],
|
|
["media", "PERMS.PAGES_VIEW"],
|
|
["photos", "PERMS.PAGES_VIEW"],
|
|
["badges", "PERMS.CATALOG_VIEW"],
|
|
["teams", "PERMS.USERS_VIEW"],
|
|
["applications", "PERMS.USERS_VIEW"],
|
|
["logs", "PERMS.LOGS_VIEW"],
|
|
["catalog", "PERMS.CATALOG_VIEW"],
|
|
["rooms/edit/[id]", "PERMS.ROOMS_EDIT"],
|
|
];
|
|
|
|
const ACTION_GATES: Array<[string, string]> = [
|
|
["admin-settings.ts", "PERMS.SETTINGS_EDIT"],
|
|
["admin-theme.ts", "PERMS.SETTINGS_EDIT"],
|
|
["admin-emulator.ts", "PERMS.SETTINGS_EDIT"],
|
|
["admin-bans.ts", "PERMS.USERS_BAN"],
|
|
["admin-wordfilter.ts", "PERMS.WORDFILTER_EDIT"],
|
|
["admin-articles.ts", "PERMS.NEWS_EDIT"],
|
|
["admin-shop.ts", "PERMS.SHOP_EDIT"],
|
|
["admin-radio-autodj.ts", "PERMS.RADIO_EDIT"],
|
|
["catalog.ts", "PERMS.CATALOG_EDIT"],
|
|
["rooms.ts", "PERMS.ROOMS_EDIT"],
|
|
["admin-vpn.ts", "PERMS.SETTINGS_EDIT"],
|
|
["admin-ads.ts", "PERMS.PAGES_EDIT"],
|
|
["admin-vouchers.ts", "PERMS.SHOP_EDIT"],
|
|
["admin-alerts.ts", "PERMS.NOTIFICATIONS_EDIT"],
|
|
["commandocentrum.ts", "PERMS.RCON_EXECUTE"],
|
|
["translations.ts", "PERMS.SETTINGS_EDIT"],
|
|
];
|
|
|
|
describe("admin operations route contract", () => {
|
|
it.each(ROUTES)("provides and guards /admin/%s", (route, permission) => {
|
|
const path = `src/app/admin/${route}/page.tsx`;
|
|
expect(existsSync(path), path).toBe(true);
|
|
expect(readFileSync(path, "utf8"), path).toContain(permission);
|
|
});
|
|
|
|
it("guards radio section via layout", () => {
|
|
const path = "src/app/admin/radio/layout.tsx";
|
|
expect(existsSync(path), path).toBe(true);
|
|
expect(readFileSync(path, "utf8"), path).toContain("PERMS.RADIO_VIEW");
|
|
});
|
|
|
|
it.each([
|
|
["analytics/export", "PERMS.ANALYTICS_EXPORT"],
|
|
["devops/health", "PERMS.DEVOPS_VIEW"],
|
|
["users/actions", "PERMS.USERS_EDIT"],
|
|
])("provides and guards /api/admin/%s", (route, permission) => {
|
|
const path = `src/app/api/admin/${route}/route.ts`;
|
|
expect(existsSync(path), path).toBe(true);
|
|
expect(readFileSync(path, "utf8"), path).toContain(permission);
|
|
});
|
|
|
|
it.each(ACTION_GATES)("guards %s with %s", (file, permission) => {
|
|
const source = readFileSync(`src/actions/${file}`, "utf8");
|
|
expect(source).toContain(permission);
|
|
expect(source).not.toMatch(/await requireStaff\(\)/);
|
|
expect(source).not.toMatch(/await requireStaffRateLimited\(\)/);
|
|
});
|
|
|
|
it("has no requireStaff left in admin action modules", () => {
|
|
const dir = "src/actions";
|
|
const offenders: string[] = [];
|
|
for (const name of readdirSync(dir)) {
|
|
if (!name.endsWith(".ts") || name.endsWith(".test.ts")) continue;
|
|
const source = readFileSync(join(dir, name), "utf8");
|
|
if (/await requireStaff(RateLimited)?\(\)/.test(source)) {
|
|
offenders.push(name);
|
|
}
|
|
}
|
|
expect(offenders).toEqual([]);
|
|
});
|
|
|
|
it("has no requireStaff left in admin pages", () => {
|
|
const root = "src/app/admin";
|
|
const offenders: string[] = [];
|
|
function walk(dir: string) {
|
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
const full = join(dir, entry.name);
|
|
if (entry.isDirectory()) walk(full);
|
|
else if (entry.name === "page.tsx") {
|
|
const source = readFileSync(full, "utf8");
|
|
if (/await requireStaff\(/.test(source)) {
|
|
offenders.push(relative(process.cwd(), full).replaceAll("\\", "/"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
walk(root);
|
|
expect(offenders).toEqual([]);
|
|
});
|
|
});
|