feat: separate internal and external open-task listing traffic
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 8s

This commit is contained in:
OG T
2026-06-07 16:08:02 +08:00
parent 3d32e4f3d5
commit 40ea6f7090
2 changed files with 69 additions and 11 deletions

View File

@@ -28,6 +28,37 @@ const MCP_AGENT_HEADERS = [
"x-openai-agent",
];
function resolveSourceIp(request: NextRequest) {
return (
request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ??
request.headers.get("x-real-ip") ??
"unknown"
);
}
function isPrivateIp(ip: string | undefined) {
if (!ip) return false;
const normalized = ip.trim().toLowerCase();
if (!normalized || normalized === "unknown" || normalized === "::1" || normalized === "localhost") {
return true;
}
if (normalized.startsWith("127.") || normalized.startsWith("10.") || normalized.startsWith("192.168.")) {
return true;
}
if (normalized.startsWith("172.")) {
const secondOctet = Number(normalized.split(".")[1]);
return secondOctet >= 16 && secondOctet <= 31;
}
if (normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe80")) {
return true;
}
return false;
}
function normalizeActorId(value: string, fallback: string) {
const normalized = value.trim().toLowerCase().replace(/[^a-z0-9._:-]+/g, "_").replace(/_+/g, "_");
return normalized.slice(0, 64) || fallback;
@@ -72,6 +103,9 @@ export async function POST(request: NextRequest, props: { params: Promise<{ tool
case "list_open_tasks": {
ListOpenTasksRequestSchema.parse(body);
const actor = resolveActorFromMcpRequest(request);
const sourceIp = resolveSourceIp(request);
const isPublicIp = !isPrivateIp(sourceIp);
const trafficAction = isPublicIp ? "EXTERNAL_LIST_OPEN_TASKS_MCP" : "INTERNAL_LIST_OPEN_TASKS_MCP";
const tasks = await prisma.task.findMany({
where: { status: TaskStatus.OPEN },
@@ -95,7 +129,7 @@ export async function POST(request: NextRequest, props: { params: Promise<{ tool
void sendTrafficAlert({
level: "info",
action: "EXTERNAL_LIST_OPEN_TASKS_MCP",
action: trafficAction,
surface: "mcp/list_open_tasks",
actorType: actor.actorType,
actorId: actor.actorId,
@@ -104,11 +138,8 @@ export async function POST(request: NextRequest, props: { params: Promise<{ tool
metadata: {
count: formattedTasks.length,
source_tool: tool,
source_ip: sourceIp,
user_agent: request.headers.get("user-agent") ?? "unknown",
source_ip:
request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ??
request.headers.get("x-real-ip") ??
"unknown",
},
});
@@ -117,13 +148,13 @@ export async function POST(request: NextRequest, props: { params: Promise<{ tool
createdAt: {
gte: new Date(Date.now() - MCP_SURGE_WINDOW_MINUTES * 60 * 1000),
},
action: "EXTERNAL_LIST_OPEN_TASKS_MCP",
action: trafficAction,
},
}).then((eventCount) => {
if (eventCount > 0 && eventCount % MCP_SURGE_INTERVAL === 0) {
void sendTrafficAlert({
level: "warning",
action: "EXTERNAL_LIST_OPEN_TASKS_SURGE",
action: isPublicIp ? "EXTERNAL_LIST_OPEN_TASKS_SURGE" : "INTERNAL_LIST_OPEN_TASKS_SURGE",
surface: "mcp/list_open_tasks",
actorType: "SYSTEM",
actorId: "traffic-monitor",

View File

@@ -49,6 +49,29 @@ function resolveSourceIp(request: Request) {
);
}
function isPrivateIp(ip: string | undefined) {
if (!ip) return false;
const normalized = ip.trim().toLowerCase();
if (!normalized || normalized === "unknown" || normalized === "::1" || normalized === "localhost") {
return true;
}
if (normalized.startsWith("127.") || normalized.startsWith("10.") || normalized.startsWith("192.168.")) {
return true;
}
if (normalized.startsWith("172.")) {
const secondOctet = Number(normalized.split(".")[1]);
return secondOctet >= 16 && secondOctet <= 31;
}
if (normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe80")) {
return true;
}
return false;
}
function isLikelyAIAgentUserAgent(userAgent: string) {
const normalized = userAgent.toLowerCase();
return AI_USER_AGENT_HINTS.some((token) => normalized.includes(token));
@@ -83,6 +106,10 @@ function resolveExternalActor(request: Request) {
}
export async function GET(request: Request) {
const sourceIp = resolveSourceIp(request);
const isPublicIp = !isPrivateIp(sourceIp);
const trafficAction = isPublicIp ? "EXTERNAL_LIST_OPEN_TASKS" : "INTERNAL_LIST_OPEN_TASKS";
const tasks = await prisma.task.findMany({
where: { status: TaskStatus.OPEN },
orderBy: { created_at: "desc" },
@@ -124,7 +151,7 @@ export async function GET(request: Request) {
void sendTrafficAlert({
level: "info",
action: "EXTERNAL_LIST_OPEN_TASKS",
action: trafficAction,
surface: "public-open-tasks",
actorType: actor.actorType,
actorId: actor.actorId,
@@ -133,7 +160,7 @@ export async function GET(request: Request) {
metadata: {
source: "public-open-tasks",
task_count: publicPayload.length,
source_ip: resolveSourceIp(request),
source_ip: sourceIp,
user_agent: request.headers.get("user-agent") ?? "unknown",
},
});
@@ -145,13 +172,13 @@ export async function GET(request: Request) {
void prisma.auditEvent.count({
where: {
createdAt: { gte: surgeWindowStart },
action: "EXTERNAL_LIST_OPEN_TASKS",
action: trafficAction,
},
}).then((eventCount) => {
if (eventCount > 0 && eventCount % 25 === 0) {
void sendTrafficAlert({
level: "warning",
action: "EXTERNAL_LIST_OPEN_TASKS_SURGE",
action: isPublicIp ? "EXTERNAL_LIST_OPEN_TASKS_SURGE" : "INTERNAL_LIST_OPEN_TASKS_SURGE",
surface: "public-open-tasks",
actorType: "SYSTEM",
actorId: "traffic-monitor",