feat(privacy): scan ingested sources for customer-identifying data
Detection-only scan (internal/privacy) attached to every AnalysisResult: a customer-domain guess plus a findings list (category, file, line, match, hint), ported from the KB grep playbook. Runs on archive uploads and the serialized Redfish tree; gated by LOGPILE_PRIVACY_SCAN (default on). Surfaced at GET /api/privacy-scan, in the "Customer data" UI panel, and as privacy_report.json in the raw-export bundle. IP policy keeps RFC1918 and example ranges out of findings; allowlist covers standards-body and vendor infrastructure domains. No customer tokens in the repo. See ADL-066 and bible-local/docs/privacy-scan.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
3311bafd8e
commit
4a4910f207
@@ -0,0 +1,59 @@
|
||||
package privacy
|
||||
|
||||
import "net"
|
||||
|
||||
// Documentation, benchmarking, and well-known example addresses that carry no
|
||||
// site information even though they are globally routable.
|
||||
var nonSensitiveNets = func() []*net.IPNet {
|
||||
cidrs := []string{
|
||||
"192.0.2.0/24", // RFC 5737 TEST-NET-1
|
||||
"198.51.100.0/24", // RFC 5737 TEST-NET-2
|
||||
"203.0.113.0/24", // RFC 5737 TEST-NET-3
|
||||
"198.18.0.0/15", // RFC 2544 benchmarking
|
||||
"100.64.0.0/10", // RFC 6598 CGNAT
|
||||
"192.88.99.0/24", // RFC 7526 6to4 relay anycast
|
||||
}
|
||||
out := make([]*net.IPNet, 0, len(cidrs))
|
||||
for _, c := range cidrs {
|
||||
if _, n, err := net.ParseCIDR(c); err == nil {
|
||||
out = append(out, n)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}()
|
||||
|
||||
var nonSensitiveExact = map[string]struct{}{
|
||||
"8.8.8.8": {}, "8.8.4.4": {}, "1.1.1.1": {}, "1.0.0.1": {},
|
||||
"4.2.2.2": {}, "4.2.2.1": {}, "9.9.9.9": {}, "1.2.3.4": {},
|
||||
"208.67.222.222": {}, "208.67.220.220": {},
|
||||
}
|
||||
|
||||
// isSensitiveIP reports whether s is a routable address that could identify the
|
||||
// customer's provider or site. Private (RFC1918/ULA), loopback, link-local,
|
||||
// multicast, and the example/benchmark ranges above are not sensitive.
|
||||
func isSensitiveIP(s string) bool {
|
||||
ip := net.ParseIP(s)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
if _, ok := nonSensitiveExact[s]; ok {
|
||||
return false
|
||||
}
|
||||
if ip.IsLoopback() || ip.IsPrivate() || ip.IsUnspecified() ||
|
||||
ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() ||
|
||||
ip.IsMulticast() || ip.IsInterfaceLocalMulticast() {
|
||||
return false
|
||||
}
|
||||
if !ip.IsGlobalUnicast() {
|
||||
return false
|
||||
}
|
||||
if v4 := ip.To4(); v4 != nil && (v4[0] == 0 || v4[0] == 255 || v4[0] >= 240) {
|
||||
return false
|
||||
}
|
||||
for _, n := range nonSensitiveNets {
|
||||
if n.Contains(ip) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user