ronantakizawa/codereview-bench huggingface dataset:
Repository: caddyserver/caddy
File: replacer.go (Go)

Code before:
// to service that key (even if the value is blank). If the
// function does not recognize the key, false should be
// returned.
type ReplacerFunc func(key string) (any, bool)

func globalDefaultReplacements(key string) (any, bool) {
	// check environment variable
	const envPrefix = "env."
	if strings.HasPrefix(key, envPrefix) {
		return os.Getenv(key[len(envPrefix):]), true
	}

	// check files
	// TODO: We may want to cache the file contents in case
	// this is used in a hot path in a config. But for now,
	// we'll just read the file every time, the kernel will
	// tend to cache the file contents for us.
	const filePrefix = "file."
	if strings.HasPrefix(key, filePrefix) {
		filename := key[len(filePrefix):]
		body, err := os.ReadFile(filename)
		if err != nil {
			wd, _ := os.Getwd()
			Log().Error("placeholder: failed to read file",
				zap.String("file", filename),
				zap.String("wd", wd),
				zap.Error(err))
			return nil, true
		}
		return body, true
	}

	switch key {
	case "system.hostname":
		// OK if there is an error; just return empty string
		name, _ := os.Hostname()
		return name, true
	case "system.slash":
		return string(filepath.Separator), true
	case "system.os":
		return runtime.GOOS, true
	case "system.wd":
		// OK if there is an error; just return empty string
		wd, _ := os.Getwd()
		return wd, true
	case "system.arch":
		return runtime.GOARCH, true
	case "time.now":
		return nowFunc(), true
	case "time.now.common_log":
		return nowFunc().Format("02/Jan/2006:15:04:05 -0700"), true

Review comment (suggestion):
```suggestion
				zap.String("working_dir", wd),
```

Code after:
	case []rune:
		return string(v)
	case int:
		return strconv.Itoa(v)
	case int32:
		return strconv.Itoa(int(v))
	case int64:
		return strconv.Itoa(int(v))
	case uint:
		return strconv.Itoa(int(v))
	case uint32:
		return strconv.Itoa(int(v))
	case uint64:
		return strconv.Itoa(int(v))
	case float32:
		return strconv.FormatFloat(float64(v), 'f', -1, 32)
	case float64:
		return strconv.FormatFloat(v, 'f', -1, 64)
	case bool:
		if v {
			return "true"
		}
		return "false"
	default:
		return fmt.Sprintf("%+v", v)
	}
}

// ReplacerFunc is a function that returns a replacement for the
// given key along with true if the function is able to service
// that key (even if the value is blank). If the function does
// not recognize the key, false should be returned.
type ReplacerFunc func(key string) (any, bool)

func (f ReplacerFunc) replace(key string) (any, bool) {
	return f(key)
}

// replacementProvider is a type that can provide replacements
// for placeholders. Allows for type assertion to determine
// which type of provider it is.
type replacementProvider interface {
	replace(key string) (any, bool)
}

// fileReplacementsProvider handles {file.*} replacements,
// reading a file from disk and replacing with its contents.
type fileReplacementProvider struct{}

func (f fileReplacementProvider) replace(key string) (any, bool) {
	if !strings.HasPrefix(key, filePrefix) {
Repository: caddyserver/caddy
File: modules/caddypki/acmeserver/acmeserver.go (Go)

Code before:

// makeClient creates an ACME client which will use a custom
// resolver instead of net.DefaultResolver.
func (ash Handler) makeClient() (acme.Client, error) {
	for _, v := range ash.Resolvers {
		addr, err := caddy.ParseNetworkAddress(v)
		if err != nil {
			// If a port wasn't specified for the resolver,
			// try defaulting to 53 and parse again
			if strings.Contains(err.Error(), "missing port in address") {
				addr, err = caddy.ParseNetworkAddress(v + ":53")
			}
			if err != nil {
				return nil, err
			}
		}
		if addr.PortRangeSize() != 1 {
			return nil, fmt.Errorf("resolver address must have exactly one address; cannot call %v", addr)
		}
		ash.resolvers = append(ash.resolvers, addr)
	}

	var resolver *net.Resolver
	if len(ash.resolvers) != 0 {
		dialer := &net.Dialer{
			Timeout: 2 * time.Second,
		}
		resolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				//nolint:gosec
				addr := ash.resolvers[weakrand.Intn(len(ash.resolvers))]
				return dialer.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
			},
		}
	} else {
		resolver = net.DefaultResolver
	}

	return resolverClient{
		Client:   acme.NewClient(),
		resolver: resolver,
		ctx:      ash.ctx,
	}, nil
}

type resolverClient struct {
	acme.Client

	resolver *net.Resolver
	ctx      context.Context

Review comment (suggestion):
I think this should use the requested `network` instead of `addr.Network`, since DNS can use both TCP and UDP.
The way it is now, the user has to specify the resolver address as `udp/127.0.0.1` to get it to work (at all).
```suggestion
				return dialer.DialContext(ctx, network, addr.JoinHostPort(0))
```

Code after:

// makeClient creates an ACME client which will use a custom
// resolver instead of net.DefaultResolver.
func (ash Handler) makeClient() (acme.Client, error) {
	for _, v := range ash.Resolvers {
		addr, err := caddy.ParseNetworkAddressWithDefaults(v, "udp", 53)
		if err != nil {
			return nil, err
		}
		if addr.PortRangeSize() != 1 {
			return nil, fmt.Errorf("resolver address must have exactly one address; cannot call %v", addr)
		}
		ash.resolvers = append(ash.resolvers, addr)
	}

	var resolver *net.Resolver
	if len(ash.resolvers) != 0 {
		dialer := &net.Dialer{
			Timeout: 2 * time.Second,
		}
		resolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				//nolint:gosec
				addr := ash.resolvers[weakrand.Intn(len(ash.resolvers))]
				return dialer.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
			},
		}
	} else {
		resolver = net.DefaultResolver
	}

	return resolverClient{
		Client:   acme.NewClient(),
		resolver: resolver,
		ctx:      ash.ctx,
	}, nil
}

type resolverClient struct {
	acme.Client

	resolver *net.Resolver
	ctx      context.Context
}

func (c resolverClient) LookupTxt(name string) ([]string, error) {
	return c.resolver.LookupTXT(c.ctx, name)
}

const defaultPathPrefix = "/acme/"
Repository: caddyserver/caddy
File: modules/caddypki/acmeserver/acmeserver.go (Go)

Code before:
		dbConfig := &db.Config{
			Type:       "bbolt",
			DataSource: dbPath,
		}
		database, err := db.New(dbConfig)
		return databaseCloser{&database}, err
	})

	if loaded {
		ash.logger.Debug("loaded preexisting CA database", zap.String("db_key", key))
	}

	return database.(databaseCloser).DB, err
}

// makeClient creates an ACME client which will use a custom
// resolver instead of net.DefaultResolver.
func (ash Handler) makeClient() (acme.Client, error) {
	for _, v := range ash.Resolvers {
		addr, err := caddy.ParseNetworkAddress(v)
		if err != nil {
			// If a port wasn't specified for the resolver,
			// try defaulting to 53 and parse again
			if strings.Contains(err.Error(), "missing port in address") {
				addr, err = caddy.ParseNetworkAddress(v + ":53")
			}
			if err != nil {
				return nil, err
			}
		}
		if addr.PortRangeSize() != 1 {
			return nil, fmt.Errorf("resolver address must have exactly one address; cannot call %v", addr)
		}
		ash.resolvers = append(ash.resolvers, addr)
	}

	var resolver *net.Resolver
	if len(ash.resolvers) != 0 {
		dialer := &net.Dialer{
			Timeout: 2 * time.Second,
		}
		resolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				//nolint:gosec
				addr := ash.resolvers[weakrand.Intn(len(ash.resolvers))]
				return dialer.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
			},
		}
	} else {
		resolver = net.DefaultResolver

Review comment (suggestion):
```suggestion
		}
		if addr.StartPort == 0 {
			addr.StartPort = 53
		}
```

Code after:
		dbConfig := &db.Config{
			Type:       "bbolt",
			DataSource: dbPath,
		}
		database, err := db.New(dbConfig)
		return databaseCloser{&database}, err
	})

	if loaded {
		ash.logger.Debug("loaded preexisting CA database", zap.String("db_key", key))
	}

	return database.(databaseCloser).DB, err
}

// makeClient creates an ACME client which will use a custom
// resolver instead of net.DefaultResolver.
func (ash Handler) makeClient() (acme.Client, error) {
	for _, v := range ash.Resolvers {
		addr, err := caddy.ParseNetworkAddressWithDefaults(v, "udp", 53)
		if err != nil {
			return nil, err
		}
		if addr.PortRangeSize() != 1 {
			return nil, fmt.Errorf("resolver address must have exactly one address; cannot call %v", addr)
		}
		ash.resolvers = append(ash.resolvers, addr)
	}

	var resolver *net.Resolver
	if len(ash.resolvers) != 0 {
		dialer := &net.Dialer{
			Timeout: 2 * time.Second,
		}
		resolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				//nolint:gosec
				addr := ash.resolvers[weakrand.Intn(len(ash.resolvers))]
				return dialer.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
			},
		}
	} else {
		resolver = net.DefaultResolver
	}

	return resolverClient{
		Client:   acme.NewClient(),
		resolver: resolver,
		ctx:      ash.ctx,
	}, nil
Repository: caddyserver/caddy
File: modules/caddypki/acmeserver/acmeserver.go (Go)

Code before:
		}
		database, err := db.New(dbConfig)
		return databaseCloser{&database}, err
	})

	if loaded {
		ash.logger.Debug("loaded preexisting CA database", zap.String("db_key", key))
	}

	return database.(databaseCloser).DB, err
}

// makeClient creates an ACME client which will use a custom
// resolver instead of net.DefaultResolver.
func (ash Handler) makeClient() (acme.Client, error) {
	for _, v := range ash.Resolvers {
		addr, err := caddy.ParseNetworkAddress(v)
		if err != nil {
			// If a port wasn't specified for the resolver,
			// try defaulting to 53 and parse again
			if strings.Contains(err.Error(), "missing port in address") {
				addr, err = caddy.ParseNetworkAddress(v + ":53")
			}
			if err != nil {
				return nil, err
			}
		}
		if addr.PortRangeSize() != 1 {
			return nil, fmt.Errorf("resolver address must have exactly one address; cannot call %v", addr)
		}
		ash.resolvers = append(ash.resolvers, addr)
	}

	var resolver *net.Resolver
	if len(ash.resolvers) != 0 {
		dialer := &net.Dialer{
			Timeout: 2 * time.Second,
		}
		resolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				//nolint:gosec
				addr := ash.resolvers[weakrand.Intn(len(ash.resolvers))]
				return dialer.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
			},
		}
	} else {
		resolver = net.DefaultResolver
	}

	return resolverClient{

Review comment (suggestion):
I don't think this is right: a port is optional for `caddy.ParseNetworkAddress`, so it does not return an error, it just sets the port to 0.

Code after:
		}
		database, err := db.New(dbConfig)
		return databaseCloser{&database}, err
	})

	if loaded {
		ash.logger.Debug("loaded preexisting CA database", zap.String("db_key", key))
	}

	return database.(databaseCloser).DB, err
}

// makeClient creates an ACME client which will use a custom
// resolver instead of net.DefaultResolver.
func (ash Handler) makeClient() (acme.Client, error) {
	for _, v := range ash.Resolvers {
		addr, err := caddy.ParseNetworkAddressWithDefaults(v, "udp", 53)
		if err != nil {
			return nil, err
		}
		if addr.PortRangeSize() != 1 {
			return nil, fmt.Errorf("resolver address must have exactly one address; cannot call %v", addr)
		}
		ash.resolvers = append(ash.resolvers, addr)
	}

	var resolver *net.Resolver
	if len(ash.resolvers) != 0 {
		dialer := &net.Dialer{
			Timeout: 2 * time.Second,
		}
		resolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				//nolint:gosec
				addr := ash.resolvers[weakrand.Intn(len(ash.resolvers))]
				return dialer.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
			},
		}
	} else {
		resolver = net.DefaultResolver
	}

	return resolverClient{
		Client:   acme.NewClient(),
		resolver: resolver,
		ctx:      ash.ctx,
	}, nil
}

type resolverClient struct {
Repository: caddyserver/caddy
File: modules/caddyhttp/server.go (Go)

Code before:
		logger = s.Logs.wrapLogger(logger, r.Host)
	}

	log := logger.Info
	if wrec.Status() >= 400 {
		log = logger.Error
	}

	userID, _ := repl.GetString("http.auth.user.id")

	reqBodyLength := 0
	if bodyReader != nil {
		reqBodyLength = bodyReader.Length
	}

	extra := r.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields)

	// preallocate with the amount of known fields
	fieldCount := 6
	fields := make([]zapcore.Field, fieldCount+len(extra.fields))
	fields[0] = zap.Int("bytes_read", reqBodyLength)
	fields[1] = zap.String("user_id", userID)
	fields[2] = zap.Duration("duration", *duration)
	fields[3] = zap.Int("size", wrec.Size())
	fields[4] = zap.Int("status", wrec.Status())
	fields[5] = zap.Object("resp_headers", LoggableHTTPHeader{
		Header:               wrec.Header(),
		ShouldLogCredentials: shouldLogCredentials,
	})

	// add extra fields after the known fields
	for i, field := range extra.fields {
		fields[fieldCount+i] = field
	}

	log("handled request", fields...)
}

// protocol returns true if the protocol proto is configured/enabled.
func (s *Server) protocol(proto string) bool {
	for _, p := range s.Protocols {
		if p == proto {
			return true
		}
	}
	return false
}

// Listeners returns the server's listeners. These are active listeners,
// so calling Accept() or Close() on them will probably break things.
// They are made available here for read-only purposes (e.g. Addr())

Review comment (suggestion):
This could probably become a direct assignment:

```go
fields := []zapcore.Field{field1, field2, ...}
```

I think that has the same result and nicer ergonomics.

Code after:
		logger = s.Logs.wrapLogger(logger, r.Host)
	}

	log := logger.Info
	if wrec.Status() >= 400 {
		log = logger.Error
	}

	userID, _ := repl.GetString("http.auth.user.id")

	reqBodyLength := 0
	if bodyReader != nil {
		reqBodyLength = bodyReader.Length
	}

	extra := r.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields)

	fieldCount := 6
	fields := make([]zapcore.Field, 0, fieldCount+len(extra.fields))
	fields = append(fields,
		zap.Int("bytes_read", reqBodyLength),
		zap.String("user_id", userID),
		zap.Duration("duration", *duration),
		zap.Int("size", wrec.Size()),
		zap.Int("status", wrec.Status()),
		zap.Object("resp_headers", LoggableHTTPHeader{
			Header:               wrec.Header(),
			ShouldLogCredentials: shouldLogCredentials,
		}))
	fields = append(fields, extra.fields...)

	log("handled request", fields...)
}

// protocol returns true if the protocol proto is configured/enabled.
func (s *Server) protocol(proto string) bool {
	for _, p := range s.Protocols {
		if p == proto {
			return true
		}
	}
	return false
}

// Listeners returns the server's listeners. These are active listeners,
// so calling Accept() or Close() on them will probably break things.
// They are made available here for read-only purposes (e.g. Addr())
// and for type-asserting for purposes where you know what you're doing.
//
// EXPERIMENTAL: Subject to change or removal.
func (s *Server) Listeners() []net.Listener { return s.listeners }
Repository: caddyserver/caddy
File: modules/caddyhttp/server.go (Go)

Code before:
	repl.Set("http.response.size", wrec.Size())
	repl.Set("http.response.duration", duration)
	repl.Set("http.response.duration_ms", duration.Seconds()*1e3) // multiply seconds to preserve decimal (see #4666)

	logger := accLog
	if s.Logs != nil {
		logger = s.Logs.wrapLogger(logger, r.Host)
	}

	log := logger.Info
	if wrec.Status() >= 400 {
		log = logger.Error
	}

	userID, _ := repl.GetString("http.auth.user.id")

	reqBodyLength := 0
	if bodyReader != nil {
		reqBodyLength = bodyReader.Length
	}

	extra := r.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields)

	// preallocate with the amount of known fields
	fieldCount := 6
	fields := make([]zapcore.Field, fieldCount+len(extra.fields))
	fields[0] = zap.Int("bytes_read", reqBodyLength)
	fields[1] = zap.String("user_id", userID)
	fields[2] = zap.Duration("duration", *duration)
	fields[3] = zap.Int("size", wrec.Size())
	fields[4] = zap.Int("status", wrec.Status())
	fields[5] = zap.Object("resp_headers", LoggableHTTPHeader{
		Header:               wrec.Header(),
		ShouldLogCredentials: shouldLogCredentials,
	})

	// add extra fields after the known fields
	for i, field := range extra.fields {
		fields[fieldCount+i] = field
	}

	log("handled request", fields...)
}

// protocol returns true if the protocol proto is configured/enabled.
func (s *Server) protocol(proto string) bool {
	for _, p := range s.Protocols {
		if p == proto {
			return true
		}
	}

Review comment (suggestion):
As discussed with Francis in Slack, these can be pooled. Doesn't have to happen in this PR, but it would reduce allocations over time as the slices will get reused.

Code after:
	repl.Set("http.response.size", wrec.Size())
	repl.Set("http.response.duration", duration)
	repl.Set("http.response.duration_ms", duration.Seconds()*1e3) // multiply seconds to preserve decimal (see #4666)

	logger := accLog
	if s.Logs != nil {
		logger = s.Logs.wrapLogger(logger, r.Host)
	}

	log := logger.Info
	if wrec.Status() >= 400 {
		log = logger.Error
	}

	userID, _ := repl.GetString("http.auth.user.id")

	reqBodyLength := 0
	if bodyReader != nil {
		reqBodyLength = bodyReader.Length
	}

	extra := r.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields)

	fieldCount := 6
	fields := make([]zapcore.Field, 0, fieldCount+len(extra.fields))
	fields = append(fields,
		zap.Int("bytes_read", reqBodyLength),
		zap.String("user_id", userID),
		zap.Duration("duration", *duration),
		zap.Int("size", wrec.Size()),
		zap.Int("status", wrec.Status()),
		zap.Object("resp_headers", LoggableHTTPHeader{
			Header:               wrec.Header(),
			ShouldLogCredentials: shouldLogCredentials,
		}))
	fields = append(fields, extra.fields...)

	log("handled request", fields...)
}

// protocol returns true if the protocol proto is configured/enabled.
func (s *Server) protocol(proto string) bool {
	for _, p := range s.Protocols {
		if p == proto {
			return true
		}
	}
	return false
}

// Listeners returns the server's listeners. These are active listeners,
Repository: caddyserver/caddy
File: listeners.go (Go)

Code before:

		sqtc.rmu.Lock()
		defer sqtc.rmu.Unlock()

		delete(sqtc.tlsConfs, tlsConfig)
		if sqtc.activeTlsConf == tlsConfig {
			// select another tls.Config, if there is none,
			// related sharedQuicListener will be destroyed anyway
			for tc := range sqtc.tlsConfs {
				sqtc.activeTlsConf = tc
				break
			}
		}
	}
	sqtc.tlsConfs[tlsConfig] = contextAndCancelFunc{ctx, wrappedCancel}
	// there should be at most 2 tls.Configs
	if len(sqtc.tlsConfs) > 2 {
		Log().Warn("quic listener tls configs are more than 2", zap.Int("number of configs", len(sqtc.tlsConfs)))
	}
	return ctx, wrappedCancel
}

// sharedQuicListener is like sharedListener, but for quic.EarlyListeners.
type sharedQuicListener struct {
	quic.EarlyListener
	sqtc *sharedQuicTlsConfig
	key  string
}

// Destruct closes the underlying QUIC listener.
func (sql *sharedQuicListener) Destruct() error {
	return sql.EarlyListener.Close()
}

// sharedPacketConn is like sharedListener, but for net.PacketConns.
type sharedPacketConn struct {
	net.PacketConn
	key string
}

// Destruct closes the underlying socket.
func (spc *sharedPacketConn) Destruct() error {
	return spc.PacketConn.Close()
}

// fakeClosedErr returns an error value that is not temporary
// nor a timeout, suitable for making the caller think the
// listener is actually closed
func fakeClosedErr(l interface{ Addr() net.Addr }) error {
	return &net.OpError{
		Op:   "accept",

Review comment (suggestion):
I think this should use the long form as well. Or maybe just simply `config` or `sharedConfig`.

Code after:

// addTLSConfig adds tls.Config to the map if not present and returns the corresponding context and its cancelFunc
// so that when cancelled, the active tls.Config will change
func (sqtc *sharedQUICTLSConfig) addTLSConfig(tlsConfig *tls.Config) (context.Context, context.CancelFunc) {
	sqtc.rmu.Lock()
	defer sqtc.rmu.Unlock()

	if cacc, ok := sqtc.tlsConfs[tlsConfig]; ok {
		return cacc.Context, cacc.CancelFunc
	}

	ctx, cancel := context.WithCancel(context.Background())
	wrappedCancel := func() {
		cancel()

		sqtc.rmu.Lock()
		defer sqtc.rmu.Unlock()

		delete(sqtc.tlsConfs, tlsConfig)
		if sqtc.activeTlsConf == tlsConfig {
			// select another tls.Config, if there is none,
			// related sharedQuicListener will be destroyed anyway
			for tc := range sqtc.tlsConfs {
				sqtc.activeTlsConf = tc
				break
			}
		}
	}
	sqtc.tlsConfs[tlsConfig] = contextAndCancelFunc{ctx, wrappedCancel}
	// there should be at most 2 tls.Configs
	if len(sqtc.tlsConfs) > 2 {
		Log().Warn("quic listener tls configs are more than 2", zap.Int("number of configs", len(sqtc.tlsConfs)))
	}
	return ctx, wrappedCancel
}

// sharedQuicListener is like sharedListener, but for quic.EarlyListeners.
type sharedQuicListener struct {
	quic.EarlyListener
	sqtc *sharedQUICTLSConfig
	key  string
}

// Destruct closes the underlying QUIC listener.
func (sql *sharedQuicListener) Destruct() error {
	return sql.EarlyListener.Close()
}

// sharedPacketConn is like sharedListener, but for net.PacketConns.
type sharedPacketConn struct {
	net.PacketConn
Repository: caddyserver/caddy
File: caddy.go (Go)

Code before:
		if err != nil {
			log.Printf("[ERROR] stop %s: %v", name, err)
		}
	}

	// clean up all modules
	ctx.cfg.cancelFunc()
}

// Validate loads, provisions, and validates
// cfg, but does not start running it.
func Validate(cfg *Config) error {
	_, err := run(cfg, false)
	if err == nil {
		cfg.cancelFunc() // call Cleanup on all modules
	}
	return err
}

// ExportStorage calls List() and Load() on the configured
// storage module and returns the underlying assets. 
func ExportStorage(cfg *Config) (files []struct{
	Name string
	Body []byte
}, err error) {
	ctx, err := run(cfg, false)
	if err != nil {
		return nil, err
	}
	
	defer cfg.cancelFunc()
	stor := ctx.Storage()
	keys, err := stor.List(ctx, "", true)
	if err != nil {
		return nil, err
	}

	for _, k := range keys {
		info, err := stor.Stat(ctx, k)
		if err != nil {
			return nil, err
		}

		if info.IsTerminal {
			v, err := stor.Load(ctx, k)
			if err != nil {
				return nil, err
			}

			file := struct{
				Name string

Review comment (suggestion):
Rather than running the config, maybe better to load and unmarshal just the `storage` portion. You could try doing something like this:

https://github.com/caddyserver/caddy/blob/cfc85ae8caf032c3ef92675a024fc5d1264ab7ce/cmd/commandfuncs.go#L693-L717

You might need to make a caddy.Context and then call LoadModule() on it though -- I haven't tried doing that in isolation like this but I'd be happy to help if that is problematic...

Code after:
			log.Printf("[ERROR] stop %s: %v", name, err)
		}
	}

	// clean up all modules
	ctx.cfg.cancelFunc()
}

// Validate loads, provisions, and validates
// cfg, but does not start running it.
func Validate(cfg *Config) error {
	_, err := run(cfg, false)
	if err == nil {
		cfg.cancelFunc() // call Cleanup on all modules
	}
	return err
}

// exitProcess exits the process as gracefully as possible,
// but it always exits, even if there are errors doing so.
// It stops all apps, cleans up external locks, removes any
// PID file, and shuts down admin endpoint(s) in a goroutine.
// Errors are logged along the way, and an appropriate exit
// code is emitted.
func exitProcess(ctx context.Context, logger *zap.Logger) {
	// let the rest of the program know we're quitting
	atomic.StoreInt32(exiting, 1)

	// give the OS or service/process manager our 2 weeks' notice: we quit
	if err := notify.Stopping(); err != nil {
		Log().Error("unable to notify service manager of stopping state", zap.Error(err))
	}

	if logger == nil {
		logger = Log()
	}
	logger.Warn("exiting; byeee!! 👋")

	exitCode := ExitCodeSuccess

	// stop all apps
	if err := Stop(); err != nil {
		logger.Error("failed to stop apps", zap.Error(err))
		exitCode = ExitCodeFailedQuit
	}

	// clean up certmagic locks
	certmagic.CleanUpOwnLocks(ctx, logger)

	// remove pidfile
	if pidfile != "" {