Execute scripts under $CERTSPOTTER_CONFIG_DIR/hooks.d, if it exists
This commit is contained in:
parent
d08ad53464
commit
fd0a2a4d44
|
@ -99,6 +99,9 @@ func defaultWatchListPathIfExists() string {
|
|||
return ""
|
||||
}
|
||||
}
|
||||
func defaultScriptDir() string {
|
||||
return filepath.Join(defaultConfigDir(), "hooks.d")
|
||||
}
|
||||
|
||||
func readWatchListFile(filename string) (monitor.WatchList, error) {
|
||||
file, err := os.Open(filename)
|
||||
|
@ -162,11 +165,6 @@ func main() {
|
|||
os.Exit(2)
|
||||
}
|
||||
|
||||
if len(flags.email) == 0 && len(flags.script) == 0 && flags.stdout == false {
|
||||
fmt.Fprintf(os.Stderr, "%s: at least one of -email, -script, or -stdout must be specified (see -help for details)\n", programName)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
config := &monitor.Config{
|
||||
LogListSource: flags.logs,
|
||||
StateDir: flags.stateDir,
|
||||
|
@ -174,11 +172,22 @@ func main() {
|
|||
StartAtEnd: flags.startAtEnd,
|
||||
Verbose: flags.verbose,
|
||||
Script: flags.script,
|
||||
ScriptDir: defaultScriptDir(),
|
||||
Email: flags.email,
|
||||
Stdout: flags.stdout,
|
||||
HealthCheckInterval: flags.healthcheck,
|
||||
}
|
||||
|
||||
if len(config.Email) == 0 && config.Script == "" && !fileExists(config.ScriptDir) && config.Stdout == false {
|
||||
fmt.Fprintf(os.Stderr, "%s: no notification methods were specified\n", programName)
|
||||
fmt.Fprintf(os.Stderr, "Please specify at least one of the following notification methods:\n")
|
||||
fmt.Fprintf(os.Stderr, " - Place one or more executable scripts in the %s directory\n", config.ScriptDir)
|
||||
fmt.Fprintf(os.Stderr, " - Specify an email address using the -email flag\n")
|
||||
fmt.Fprintf(os.Stderr, " - Specify the path to an executable script using the -script flag\n")
|
||||
fmt.Fprintf(os.Stderr, " - Specify the -stdout flag\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if flags.watchlist == "-" {
|
||||
watchlist, err := monitor.ReadWatchList(os.Stdin)
|
||||
if err != nil {
|
||||
|
|
|
@ -21,6 +21,7 @@ type Config struct {
|
|||
Verbose bool
|
||||
SaveCerts bool
|
||||
Script string
|
||||
ScriptDir string
|
||||
Email []string
|
||||
Stdout bool
|
||||
HealthCheckInterval time.Duration
|
||||
|
|
|
@ -12,9 +12,12 @@ package monitor
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
@ -44,6 +47,12 @@ func notify(ctx context.Context, config *Config, notif notification) error {
|
|||
}
|
||||
}
|
||||
|
||||
if config.ScriptDir != "" {
|
||||
if err := execScriptDir(ctx, config.ScriptDir, notif); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -104,6 +113,32 @@ func execScript(ctx context.Context, scriptName string, notif notification) erro
|
|||
}
|
||||
}
|
||||
|
||||
func execScriptDir(ctx context.Context, dirPath string, notif notification) error {
|
||||
dirents, err := os.ReadDir(dirPath)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("error executing scripts in directory %q: %w", dirPath, err)
|
||||
}
|
||||
for _, dirent := range dirents {
|
||||
if strings.HasPrefix(dirent.Name(), ".") {
|
||||
continue
|
||||
}
|
||||
scriptPath := filepath.Join(dirPath, dirent.Name())
|
||||
info, err := os.Stat(scriptPath)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("error executing %q in directory %q: %w", dirent.Name(), dirPath, err)
|
||||
} else if info.Mode().IsRegular() && isExecutable(info.Mode()) {
|
||||
if err := execScript(ctx, scriptPath, notif); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isExecutable(mode os.FileMode) bool {
|
||||
return mode&0111 != 0
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue