feat(security): recovery alerts, gate-block sharing, rolling-window burst and admin breakdown for CrowdSec
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Successful in 1m50s
CI / tests-ui (push) Successful in 2m42s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m3s
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Successful in 1m50s
CI / tests-ui (push) Successful in 2m42s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m3s
This commit is contained in:
1 parent
301edd2c9a
commit
3e1a3f92c8
8 files changed
+448
-65
No files matched your search
@@ -6,7 +6,16 @@ import { enforceDdosRateLimit } from "@/lib/ddos-guard";
|
||||
|
||||
// The gate's block escalation (and thus the CrowdSec hook) only runs when
|
||||
// Redis is reachable, so the integration test drives a small in-memory fake.
|
||||
const state = vi.hoisted(() => ({ map: new Map<string, string>() }));
|
||||
const state = vi.hoisted(() => ({
|
||||
map: new Map<string, string>(),
|
||||
z: new Map<string, Array<[number, string]>>(),
|
||||
sendAlert: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/services/alert", () => ({
|
||||
sendAlert: state.sendAlert,
|
||||
ddosDetected: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/redis", () => ({
|
||||
redis: {
|
||||
@@ -31,8 +40,24 @@ vi.mock("@/lib/redis", () => ({
|
||||
state.map.set(key, String(next));
|
||||
return next;
|
||||
},
|
||||
expire: async () => 1,
|
||||
pexpire: async () => 1,
|
||||
pttl: async () => 60_000,
|
||||
zadd: async (key: string, score: number, member: string) => {
|
||||
const list = state.z.get(key) ?? [];
|
||||
list.push([score, member]);
|
||||
list.sort((a, b) => a[0] - b[0]);
|
||||
state.z.set(key, list);
|
||||
return 1;
|
||||
},
|
||||
zremrangebyscore: async (key: string, min: number, max: number) => {
|
||||
const list = (state.z.get(key) ?? []).filter(
|
||||
([score]) => score < min || score > max,
|
||||
);
|
||||
state.z.set(key, list);
|
||||
return 1;
|
||||
},
|
||||
zcard: async (key: string) => (state.z.get(key) ?? []).length,
|
||||
sadd: async (key: string, member: string) => {
|
||||
const members = new Set(
|
||||
(state.map.get(key) ?? "").split("\u0001").filter(Boolean),
|
||||
@@ -95,6 +120,8 @@ describe("anti-DDoS automatic CrowdSec blocks", () => {
|
||||
vi.unstubAllGlobals();
|
||||
vi.unstubAllEnvs();
|
||||
state.map.clear();
|
||||
state.z.clear();
|
||||
state.sendAlert.mockReset();
|
||||
resetCrowdsecCache();
|
||||
invalidateAntiddosConfig();
|
||||
fetchMock = vi.fn();
|
||||
|
||||
Reference in new issue
Block a user