include db for gitea build
Build and Publish / Metadata (push) Successful in 10s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 2m16s

This commit is contained in:
mats committed 2026-09-20 11:01:56 +02:00
1 parent 8de4a2e010
commit 645f923175
33 files changed
+1490 -150

No files matched your search

+67
View File
@@ -0,0 +1,67 @@
// Resolves the real client of a trace. One request is recorded by several
// spans (ingress outer span, ingress inner span on a loopback hop, the app
// span) and only the outer one sees the public peer, so a single span's
// net.peer.ip is often 127.0.0.1 or a pod address. The Go side does the same
// walk in internal/tracectx; keep the two definitions of "public" in step.
import type { ProcessedSpan, ProcessedTrace } from "../components/TraceVisualization"
const PEER_KEYS = ["net.peer.ip", "client.address", "network.peer.address", "net.sock.peer.addr"]
const inRange = (a: number, b: number, lo: number, hi: number) => a === lo && b >= 0 && b <= hi
/** True for addresses that could be a real remote client: not loopback, private, link-local, CGNAT or reserved. */
export const isPublicIp = (ip: string): boolean => {
const v = ip.trim().toLowerCase()
if (!v) return false
if (v.includes(":")) {
return !(v === "::1" || v === "::" || v.startsWith("fe80:") || v.startsWith("fc") || v.startsWith("fd") || v.startsWith("ff") || v.startsWith("::ffff:"))
}
const parts = v.split(".").map(Number)
if (parts.length !== 4 || parts.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return false
const [a, b] = parts
if (a === 0 || a === 10 || a === 127 || a >= 224) return false
if (a === 169 && b === 254) return false
if (inRange(a, b, 172, 31) && b >= 16) return false
if (a === 192 && b === 168) return false
if (a === 100 && b >= 64 && b <= 127) return false // CGNAT / Tailscale
if (a === 198 && (b === 18 || b === 19)) return false
return true
}
export interface TraceClient {
ip: string
service: string
spanId: string
/** Ancestors between the outermost span and the span that carried the address (0 = outermost). */
depth: number
/** True when at least one span in the trace saw only an internal hop (loopback / pod / NAT). */
hadInternalHops: boolean
}
/** The public peer address seen closest to the outside of the trace, or null when every hop is internal. */
export const resolveTraceClient = (trace: ProcessedTrace): TraceClient | null => {
const byId = new Map<string, ProcessedSpan>(trace.spans.map((s) => [s.spanId, s]))
const depthOf = (span: ProcessedSpan): number => {
let depth = 0
let cur: ProcessedSpan | undefined = span
while (cur?.parentSpanId && depth < 32) {
cur = byId.get(cur.parentSpanId)
if (!cur) break
depth++
}
return depth
}
let best: TraceClient | null = null
let internal = false
for (const span of trace.spans) {
const ip = PEER_KEYS.map((k) => span.formattedAttributes[k]).find(Boolean)
if (!ip) continue
if (!isPublicIp(ip)) {
internal = true
continue
}
const depth = depthOf(span)
if (!best || depth < best.depth) best = { ip, service: span.service, spanId: span.spanId, depth, hadInternalHops: false }
}
return best ? { ...best, hadInternalHops: internal } : null
}
+3
View File
@@ -17,3 +17,6 @@ export const UA_CLASSES: { value: string; label: string }[] = [
export const uaClassLabel = (value?: string): string =>
UA_CLASSES.find((c) => c.value === value)?.label ?? value ?? ""
/** Classes the "Hide crawlers" toggle hides: self-declared crawlers, agents and scanners, not monitors or HTTP libraries. */
export const CRAWLER_CLASSES = ["ai_crawler", "ai_agent", "search_crawler", "seo_crawler", "scan_tool", "other_bot"]