@marcel91200 / caddy Mirror · read-only / commits / 2cb7ebca
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 06:00 UTC

caddyfile: fix importGraph self-loop and stale-edge bugs (#7971)

- willCycle now reports a cycle when from == to, so addEdge rejects self-loops (a self-importing file was previously accepted). - removeNode now drops the removed node's outgoing edges and any incoming edges pointing at it, keeping the adjacency map consistent. Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>

Mohammed Al Sahaf committed Sep 3, 2026 at 00:48 UTC 2cb7ebca45913da5824b7b2b4ef845d7e80da41d
2 files changed +52
caddyconfig/caddyfile/importgraph.go
+7
@@ -44,6 +44,10 @@ func (i *importGraph) addNodes(names []string) {
44
45 func (i *importGraph) removeNode(name string) {
46 delete(i.nodes, name)
47 + delete(i.edges, name)
48 + for k, targets := range i.edges {
49 + i.edges[k] = slices.DeleteFunc(targets, func(t string) bool { return t == name })
50 + }
51 }
52
53 func (i *importGraph) removeNodes(names []string) {
@@ -96,6 +100,9 @@ func (i *importGraph) areConnected(from, to string) bool {
100 }
101
102 func (i *importGraph) willCycle(from, to string) bool {
103 + if from == to {
104 + return true
105 + }
106 collector := make(map[string]bool)
107
108 var visit func(string)
caddyconfig/caddyfile/importgraph_test.go new
+45
@@ -0,0 +1,45 @@
1 +// Copyright 2015 Matthew Holt and The Caddy Authors
2 +//
3 +// Licensed under the Apache License, Version 2.0 (the "License");
4 +// you may not use this file except in compliance with the License.
5 +// You may obtain a copy of the License at
6 +//
7 +// http://www.apache.org/licenses/LICENSE-2.0
8 +//
9 +// Unless required by applicable law or agreed to in writing, software
10 +// distributed under the License is distributed on an "AS IS" BASIS,
11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 +// See the License for the specific language governing permissions and
13 +// limitations under the License.
14 +
15 +package caddyfile
16 +
17 +import "testing"
18 +
19 +func TestImportGraphSelfLoop(t *testing.T) {
20 + g := &importGraph{}
21 + g.addNode("a")
22 +
23 + if err := g.addEdge("a", "a"); err == nil {
24 + t.Error("expected error for self-loop cycle a -> a")
25 + }
26 +}
27 +
28 +func TestImportGraphRemoveNodeCleansEdges(t *testing.T) {
29 + g := &importGraph{}
30 + g.addNodes([]string{"a", "b", "c"})
31 + _ = g.addEdge("a", "b")
32 + _ = g.addEdge("b", "c")
33 +
34 + g.removeNode("b")
35 +
36 + if g.exists("b") {
37 + t.Error("node 'b' should not exist after removeNode")
38 + }
39 + if targets, ok := g.edges["b"]; ok && len(targets) > 0 {
40 + t.Errorf("outgoing edges from removed node 'b' should be cleared, got %v", targets)
41 + }
42 + if g.areConnected("a", "b") {
43 + t.Error("incoming edge 'a' -> 'b' should be removed when 'b' is removed")
44 + }
45 +}