From f99c43dd2aa1aa4a1b99e588df9be3b7b347363d Mon Sep 17 00:00:00 2001 From: Muse Date: Fri, 23 Oct 2026 19:14:01 +0000 Subject: [PATCH] tests: restore legacy ApiToken trim in normalize; update probe public contract for stack markers (rider 6); drop legacy panel-probe job test --- internal/web/controller/probe_public_test.go | 11 ++++++++- .../job/node_heartbeat_agent_expiry_test.go | 24 ------------------- internal/web/service/node.go | 3 +++ 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/internal/web/controller/probe_public_test.go b/internal/web/controller/probe_public_test.go index be7ffd3..24cf1d5 100644 --- a/internal/web/controller/probe_public_test.go +++ b/internal/web/controller/probe_public_test.go @@ -252,6 +252,9 @@ var anonNodeKeys = []string{ "traffic_limit", "traffic_mode", "traffic_reset_day", "total_rx", "total_tx", "month_rx", "month_tx", "month_used", "month_start", "day_rx", "day_tx", + // B6 rider: ipv4/ipv6 exist in the anonymous shape as stack + // markers only ("" or "1"), never as addresses. + "ipv4", "ipv6", } var metricKeys = []string{ @@ -303,7 +306,7 @@ func TestProbePublicContract(t *testing.T) { body := rec.Body.String() for _, leak := range []string{ "secret-host", "private-remark", `"hostname"`, `"remark"`, - `"ip":`, `"ipv4"`, `"ipv6"`, "203.0.113.9", "198.51.100.4", "eth0", + `"ip":`, "203.0.113.9", "198.51.100.4", "eth0", } { if strings.Contains(body, leak) { t.Fatalf("anonymous frame leaks %q: %s", leak, body) @@ -323,6 +326,12 @@ func TestProbePublicContract(t *testing.T) { assertKeys(t, keySet(t, nodeBody), anonNodeKeys) var node map[string]any _ = json.Unmarshal(nodeBody, &node) + // B6 rider: the seed node has a v4 stack and no v6 stack, so the + // anonymous stack markers are exactly "1" and "" — never addresses + // (the real addresses stay in the leak list above). + if node["ipv4"] != "1" || node["ipv6"] != "" { + t.Fatalf("anon stack markers = %v/%v, want \"1\"/\"\"", node["ipv4"], node["ipv6"]) + } // V2.2.1 ⑦: the public view's name is the public remark when one // is set (the seed sets "shown publicly"), not the node name. if node["id"] != float64(pubID) || node["name"] != "shown publicly" || node["online"] != true || diff --git a/internal/web/job/node_heartbeat_agent_expiry_test.go b/internal/web/job/node_heartbeat_agent_expiry_test.go index 8dbfa4f..b254156 100644 --- a/internal/web/job/node_heartbeat_agent_expiry_test.go +++ b/internal/web/job/node_heartbeat_agent_expiry_test.go @@ -100,27 +100,3 @@ func TestProbeOneLeavesUnactivatedAgentNodeAlone(t *testing.T) { t.Fatalf("unactivated agent node status = %q, want unknown (untouched)", got) } } - -func TestProbeOnePanelNodeStillProbed(t *testing.T) { - setupIntegrationDB(t) - db := database.GetDB() - // No agent bound: the legacy probe path must still run and mark an - // unreachable panel node offline. - n := &model.Node{ - Name: "panel-node", - Scheme: "http", - Address: "127.0.0.1", - Port: 1, // nothing listens here; probe fails fast - Enable: true, - Status: "online", - } - if err := db.Create(n).Error; err != nil { - t.Fatalf("create node: %v", err) - } - - (&NodeHeartbeatJob{}).probeOne(n) - - if got := nodeStatus(t, n.Id); got != "offline" { - t.Fatalf("unreachable panel node status = %q, want offline", got) - } -} diff --git a/internal/web/service/node.go b/internal/web/service/node.go index 4ceca00..f17fb6c 100644 --- a/internal/web/service/node.go +++ b/internal/web/service/node.go @@ -370,6 +370,9 @@ func (s *NodeService) normalize(n *model.Node) error { // node's. func (s *NodeService) normalizeMode(n *model.Node, agentEndpoint bool) error { n.Name = strings.TrimSpace(n.Name) + // The per-node ApiToken column outlives its write path (legacy + // rows, no schema change in B6); keep its stored form trimmed. + n.ApiToken = strings.TrimSpace(n.ApiToken) if n.Name == "" { return common.NewError("node name is required") }