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

- 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:
openhands committed 2026-09-22 22:22:51 +02:00
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",