feat(security): Cloudflare-aware IP trust and admin-tunable anti-DDoS
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 33s
CI / tests-integration (push) Successful in 1m50s
CI / tests-unit (push) Successful in 1m52s
CI / tests-ui (push) Successful in 2m43s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m32s
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 33s
CI / tests-integration (push) Successful in 1m50s
CI / tests-unit (push) Successful in 1m52s
CI / tests-ui (push) Successful in 2m43s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m32s
- resolveClientIp: trust cf-connecting-ip only behind cf-ray/cdn-loop, use nginx x-real-ip otherwise (anti-spoof) - antiddos-config: Redis-backed live config (antiddos:config) with 30s cache, 13 ANTI_DDOS_* env vars - ddos-guard: consume tunable rates/tiers via getAntiddosConfig - admin panel at /admin/devops/antiddos (save/reset/unban actions, PERMS.SETTINGS_VIEW) - register new admin page in housekeeping migration matrix (146 -> 147)
This commit is contained in:
1 parent
fd4d0fa1cb
commit
f0c27eb815
17 files changed
+1151
-63
No files matched your search
@@ -621,15 +621,15 @@ describe("housekeeping foundation completion contracts", () => {
|
||||
expect(html).toContain(`>${sentinel}</button>`);
|
||||
});
|
||||
|
||||
it("validates the complete 146-row migration matrix without issues", () => {
|
||||
it("validates the complete 147-row migration matrix without issues", () => {
|
||||
const discovered = discoverLegacyPages();
|
||||
const issues = validateMigrationEntries(
|
||||
discovered,
|
||||
HOUSEKEEPING_MIGRATION_MATRIX,
|
||||
);
|
||||
|
||||
expect(HOUSEKEEPING_MIGRATION_MATRIX).toHaveLength(146);
|
||||
expect(discovered).toHaveLength(146);
|
||||
expect(HOUSEKEEPING_MIGRATION_MATRIX).toHaveLength(147);
|
||||
expect(discovered).toHaveLength(147);
|
||||
expect(issues).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -29,7 +29,7 @@ describe("discoverLegacyPages", () => {
|
||||
it("discovers the exact legacy administration inventory", () => {
|
||||
const pages = discoverLegacyPages();
|
||||
|
||||
expect(pages).toHaveLength(146);
|
||||
expect(pages).toHaveLength(147);
|
||||
expect(pages).toContainEqual({
|
||||
surface: "admin",
|
||||
legacyPath: "/admin/users/:id/edit",
|
||||
|
||||
@@ -4,10 +4,10 @@ import { HOUSEKEEPING_MIGRATION_MATRIX } from "./matrix";
|
||||
import { validateMigrationEntries } from "./validate-matrix";
|
||||
|
||||
describe("HOUSEKEEPING_MIGRATION_MATRIX", () => {
|
||||
it("covers all 146 legacy pages exactly once", () => {
|
||||
it("covers all 147 legacy pages exactly once", () => {
|
||||
const discovered = discoverLegacyPages();
|
||||
|
||||
expect(HOUSEKEEPING_MIGRATION_MATRIX).toHaveLength(146);
|
||||
expect(HOUSEKEEPING_MIGRATION_MATRIX).toHaveLength(147);
|
||||
expect(
|
||||
validateMigrationEntries(discovered, HOUSEKEEPING_MIGRATION_MATRIX),
|
||||
).toEqual([]);
|
||||
|
||||
@@ -18,8 +18,8 @@ const SYSTEM_PREFIXES = [
|
||||
] as const;
|
||||
|
||||
describe("systemMigrationEntries", () => {
|
||||
it("covers all 23 System pages exactly once", () => {
|
||||
expect(systemMigrationEntries).toHaveLength(23);
|
||||
it("covers all 24 System pages exactly once", () => {
|
||||
expect(systemMigrationEntries).toHaveLength(24);
|
||||
expect(
|
||||
validateMigrationEntries(
|
||||
ownedLegacyPages(SYSTEM_PREFIXES),
|
||||
|
||||
@@ -272,6 +272,36 @@ export const systemMigrationEntries: readonly MigrationEntry[] = [
|
||||
localization: "PARTIAL",
|
||||
accessibility: "PARTIAL",
|
||||
}),
|
||||
plannedSystemEntry({
|
||||
surface: "admin",
|
||||
legacyPath: "/admin/devops/antiddos",
|
||||
sourceFile: "src/app/admin/devops/antiddos/page.tsx",
|
||||
targetPath: "/admin/system/configuration/antiddos",
|
||||
decision: "REHOST",
|
||||
capabilities: {
|
||||
read: [PERMS.SETTINGS_VIEW],
|
||||
mutate: [PERMS.SETTINGS_EDIT],
|
||||
},
|
||||
dependencies: {
|
||||
queries: [
|
||||
"antiddos:config override",
|
||||
"WebsiteSetting antiddos_*",
|
||||
"blocked anti-DDoS IPs",
|
||||
"GET /api/health",
|
||||
],
|
||||
mutations: [
|
||||
"saveAntiddosSettings",
|
||||
"resetAntiddosSettings",
|
||||
"unbanAntiddosIp",
|
||||
],
|
||||
},
|
||||
auditRequirement: "MUTATION",
|
||||
localization: "PARTIAL",
|
||||
accessibility: "PARTIAL",
|
||||
notes: [
|
||||
"Tunable anti-DDoS rates and block tiers; Cloudflare detection is read-only and driven by cf-ray/cdn-loop presence",
|
||||
],
|
||||
}),
|
||||
plannedSystemEntry({
|
||||
surface: "admin",
|
||||
legacyPath: "/admin/emulator",
|
||||
|
||||
Reference in new issue
Block a user