Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions internal/bootstrap/config_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,15 @@ func loadConfigFromYAML(cfg *Config, filePath string) error {
return nil
}

// isConfigFileNotFound returns true if the error indicates the config file does not exist.
// Handles both viper's ConfigFileNotFoundError and OS-level file-not-found errors.
// isConfigFileNotFound returns true if the error indicates the config file cannot be read
// due to absence or restrictive permissions. In distroless containers, attempting to open
// a file under a root-owned directory may return EACCES instead of ENOENT. Both cases
// should fall back gracefully to env-only configuration.
func isConfigFileNotFound(err error) bool {
var notFoundErr viper.ConfigFileNotFoundError
if errors.As(err, &notFoundErr) {
return true
}

return os.IsNotExist(err)
return os.IsNotExist(err) || os.IsPermission(err) || errors.Is(err, os.ErrPermission)
}
11 changes: 11 additions & 0 deletions internal/bootstrap/config_yaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package bootstrap

import (
"fmt"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -499,6 +500,16 @@ func TestIsConfigFileNotFound(t *testing.T) {
err: viper.ConfigFileNotFoundError{},
expected: true,
},
{
name: "permission denied error",
err: os.ErrPermission,
expected: true,
},
{
name: "wrapped permission denied error",
err: fmt.Errorf("read config: %w", os.ErrPermission),
expected: true,
},
{
name: "generic error",
err: assert.AnError,
Expand Down
Loading