From 5653af749146ffb855a47a5fb5a3b80fd9cb9662 Mon Sep 17 00:00:00 2001 From: The-Inceptions <83852285+The-Inceptions@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:37:42 +0000 Subject: [PATCH] Added watchlist reload via SIGHUP Signed-off-by: The-Inceptions <83852285+The-Inceptions@users.noreply.github.com> --- cmd/certspotter/main.go | 28 +++++++++++++++++++++++++--- merkletree/collapsed_tree.go | 34 ++++++++++++++++++++++++---------- monitor/state.go | 5 +++-- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/cmd/certspotter/main.go b/cmd/certspotter/main.go index 7779457..6089326 100644 --- a/cmd/certspotter/main.go +++ b/cmd/certspotter/main.go @@ -124,6 +124,27 @@ func readWatchListFile(filename string) (monitor.WatchList, error) { return monitor.ReadWatchList(file) } +func setupSignalListener(ctx context.Context, filename string, watchList *monitor.WatchList) { + sighup := make(chan os.Signal, 1) + signal.Notify(sighup, syscall.SIGHUP) + + go func() { + for { + select { + case <-sighup: + newWatchList, err := readWatchListFile(filename) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading watchlist file: %v", err.Error()) + continue + } + *watchList = newWatchList + case <-ctx.Done(): + return + } + } + }() +} + func readEmailFile(filename string) ([]string, error) { file, err := os.Open(filename) if err != nil { @@ -226,6 +247,9 @@ func main() { os.Exit(2) } + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + if flags.watchlist == "-" { watchlist, err := monitor.ReadWatchList(os.Stdin) if err != nil { @@ -240,11 +264,9 @@ func main() { os.Exit(1) } config.WatchList = watchlist + setupSignalListener(ctx, flags.watchlist, &config.WatchList) } - ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) - defer stop() - if err := monitor.Run(ctx, config); err != nil && !errors.Is(err, context.Canceled) { fmt.Fprintf(os.Stderr, "%s: %s\n", programName, err) os.Exit(1) diff --git a/merkletree/collapsed_tree.go b/merkletree/collapsed_tree.go index f3dcd25..09eadb7 100644 --- a/merkletree/collapsed_tree.go +++ b/merkletree/collapsed_tree.go @@ -30,10 +30,11 @@ func EmptyCollapsedTree() *CollapsedTree { } func NewCollapsedTree(nodes []Hash, size uint64) (*CollapsedTree, error) { - if len(nodes) != calculateNumNodes(size) { - return nil, fmt.Errorf("nodes has wrong length (should be %d, not %d)", calculateNumNodes(size), len(nodes)) + tree := new(CollapsedTree) + if err := tree.Init(nodes, size); err != nil { + return nil, err } - return &CollapsedTree{nodes: nodes, size: size}, nil + return tree, nil } func CloneCollapsedTree(source *CollapsedTree) *CollapsedTree { @@ -53,9 +54,11 @@ func (tree *CollapsedTree) Add(hash Hash) { } func (tree *CollapsedTree) Append(other *CollapsedTree) error { - maxSize := uint64(1) << bits.TrailingZeros64(tree.size) - if other.size > maxSize { - return fmt.Errorf("tree of size %d is too large to append to a tree of size %d (maximum size is %d)", other.size, tree.size, maxSize) + if tree.size > 0 { + maxSize := uint64(1) << bits.TrailingZeros64(tree.size) + if other.size > maxSize { + return fmt.Errorf("tree of size %d is too large to append to a tree of size %d (maximum size is %d)", other.size, tree.size, maxSize) + } } tree.nodes = append(tree.nodes, other.nodes...) @@ -86,6 +89,10 @@ func (tree *CollapsedTree) CalculateRoot() Hash { return hash } +func (tree *CollapsedTree) Nodes() []Hash { + return tree.nodes +} + func (tree *CollapsedTree) Size() uint64 { return tree.size } @@ -105,10 +112,17 @@ func (tree *CollapsedTree) UnmarshalJSON(b []byte) error { if err := json.Unmarshal(b, &rawTree); err != nil { return fmt.Errorf("error unmarshalling Collapsed Merkle Tree: %w", err) } - if len(rawTree.Nodes) != calculateNumNodes(rawTree.Size) { - return fmt.Errorf("error unmarshalling Collapsed Merkle Tree: nodes has wrong length (should be %d, not %d)", calculateNumNodes(rawTree.Size), len(rawTree.Nodes)) + if err := tree.Init(rawTree.Nodes, rawTree.Size); err != nil { + return fmt.Errorf("error unmarshalling Collapsed Merkle Tree: %w", err) } - tree.size = rawTree.Size - tree.nodes = rawTree.Nodes + return nil +} + +func (tree *CollapsedTree) Init(nodes []Hash, size uint64) error { + if len(nodes) != calculateNumNodes(size) { + return fmt.Errorf("nodes has wrong length (should be %d, not %d)", calculateNumNodes(size), len(nodes)) + } + tree.size = size + tree.nodes = nodes return nil } diff --git a/monitor/state.go b/monitor/state.go index 6595988..48097e4 100644 --- a/monitor/state.go +++ b/monitor/state.go @@ -61,7 +61,8 @@ type StateProvider interface { // feailure is not associated with a log. NotifyHealthCheckFailure(context.Context, *loglist.Log, HealthCheckFailure) error - // Called when an error occurs. The log is nil if the error is - // not associated with a log. Note that most errors are transient. + // Called when a non-fatal error occurs. The log is nil if the error is + // not associated with a log. Note that most errors are transient, and + // certspotter will retry the failed operation later. NotifyError(context.Context, *loglist.Log, error) error }