fix: recover config from unparseable ENV file entries
An ENV file holding an entry the parser rejects made every config read for that app fail outright, so the existing recovery that drops invalid keys and rewrites the file never had a chance to run. This went unnoticed because two environment test fixtures had gone stale against parser leniency that no longer exists, and the module manifest was out of date enough that its tests refused to run at all.
This commit is contained in:
@@ -396,20 +396,28 @@ func prettyPrintEnvEntries(prefix string, entries map[string]string) string {
|
|||||||
|
|
||||||
func loadFromFile(name string, filename string) (env *Env, err error) {
|
func loadFromFile(name string, filename string) (env *Env, err error) {
|
||||||
envMap := make(map[string]string)
|
envMap := make(map[string]string)
|
||||||
|
dirty := false
|
||||||
if filename == "-" {
|
if filename == "-" {
|
||||||
envMap, err = godotenv.Parse(os.Stdin)
|
envMap, err = godotenv.Parse(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(filename); err == nil {
|
if _, statErr := os.Stat(filename); statErr == nil {
|
||||||
envMap, err = godotenv.Read(filename)
|
contents, readErr := os.ReadFile(filename)
|
||||||
if err != nil {
|
if readErr != nil {
|
||||||
return nil, err
|
return nil, readErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parsed, parseErr := godotenv.Unmarshal(string(contents))
|
||||||
|
if parseErr != nil {
|
||||||
|
common.LogInfo1(fmt.Sprintf("Discarding unparseable entries from config for %s: %s", name, parseErr))
|
||||||
|
parsed = parseLineByLine(string(contents))
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
|
envMap = parsed
|
||||||
}
|
}
|
||||||
|
|
||||||
dirty := false
|
|
||||||
for k := range envMap {
|
for k := range envMap {
|
||||||
if err := validateKey(k); err != nil {
|
if err := validateKey(k); err != nil {
|
||||||
common.LogInfo1(fmt.Sprintf("Deleting invalid key %s from config for %s", k, name))
|
common.LogInfo1(fmt.Sprintf("Deleting invalid key %s from config for %s", k, name))
|
||||||
@@ -431,6 +439,23 @@ func loadFromFile(name string, filename string) (env *Env, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseLineByLine parses ENVFILE contents a line at a time, discarding the
|
||||||
|
// lines the parser rejects, so that a single malformed entry does not make the
|
||||||
|
// rest of the environment unreadable
|
||||||
|
func parseLineByLine(contents string) map[string]string {
|
||||||
|
envMap := make(map[string]string)
|
||||||
|
for _, line := range strings.Split(contents, "\n") {
|
||||||
|
lineMap, err := godotenv.Unmarshal(line)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for key, value := range lineMap {
|
||||||
|
envMap[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return envMap
|
||||||
|
}
|
||||||
|
|
||||||
func loadFromFileJSON(name string, filename string) (env *Env, err error) {
|
func loadFromFileJSON(name string, filename string) (env *Env, err error) {
|
||||||
envMap := make(map[string]string)
|
envMap := make(map[string]string)
|
||||||
if filename == "-" {
|
if filename == "-" {
|
||||||
|
|||||||
@@ -46,14 +46,16 @@ func TestMerge(t *testing.T) {
|
|||||||
e.Merge(e2)
|
e.Merge(e2)
|
||||||
Expect(e.Map()).To(Equal(pairs("BAR", "baz", "FOO", "bar")))
|
Expect(e.Map()).To(Equal(pairs("BAR", "baz", "FOO", "bar")))
|
||||||
|
|
||||||
e3, _ := newEnvFromString("FOO='ba \\nz'")
|
e3, err := newEnvFromString("FOO=\"ba \\nz\"")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
e.Merge(e3)
|
e.Merge(e3)
|
||||||
Expect(e.Map()).To(Equal(pairs("BAR", "baz", "FOO", "ba \nz")))
|
Expect(e.Map()).To(Equal(pairs("BAR", "baz", "FOO", "ba \nz")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExport(t *testing.T) {
|
func TestExport(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
e, _ := newEnvFromString("BAR='BAZ'\nFOO='b'ar '\nBAZ='a\\nb'")
|
e, err := newEnvFromString("BAR='BAZ'\nFOO=\"b'ar \"\nBAZ=\"a\\nb\"")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(e.Export(ExportFormatEnvfile)).To(Equal("BAR=\"BAZ\"\nBAZ=\"a\\nb\"\nFOO=\"b'ar \""))
|
Expect(e.Export(ExportFormatEnvfile)).To(Equal("BAR=\"BAZ\"\nBAZ=\"a\\nb\"\nFOO=\"b'ar \""))
|
||||||
Expect(e.Export(ExportFormatDockerArgs)).To(Equal("--env=BAR='BAZ' --env=BAZ='a\nb' --env=FOO='b'\\''ar '"))
|
Expect(e.Export(ExportFormatDockerArgs)).To(Equal("--env=BAR='BAZ' --env=BAZ='a\nb' --env=FOO='b'\\''ar '"))
|
||||||
Expect(e.Export(ExportFormatDockerArgsKeys)).To(Equal("--env=BAR --env=BAZ --env=FOO"))
|
Expect(e.Export(ExportFormatDockerArgsKeys)).To(Equal("--env=BAR --env=BAZ --env=FOO"))
|
||||||
|
|||||||
Reference in New Issue
Block a user