Repository: superfly/flyctl (Go)

Issue:
flyctl secrets import should allow whitespace between key, value, and =
**Describe the bug**
Secrets import still doesn't allow whitespace between key, value, and =.

```text
$ cat /etc/os-release
NAME="Pop!_OS"
VERSION="22.04 LTS"
ID=pop
ID_LIKE="ubuntu debian"
PRETTY_NAME="Pop!_OS 22.04 LTS"
VERSION_ID="22.04"
HOME_URL="https://pop.system76.com"
SUPPORT_URL="https://support.system76.com"
BUG_REPORT_URL="https://github.com/pop-os/pop/issues"
PRIVACY_POLICY_URL="https://system76.com/privacy"
VERSION_CODENAME=jammy
UBUNTU_CODENAME=jammy
LOGO=distributor-logo-pop-os

$ flyctl version
flyctl v0.1.119 linux/amd64 Commit: e2d15d62a963c6a86daeefcfb435788575ba98f1 BuildDate: 2023-11-06T22:46:27Z
```

**Command output:**

```text
$ cat .env
APP_ENV = production

$ cat .env | flyctl secrets import
Error: Validation failed: Name only allows letters, numbers, and underscores
```

Relates to: https://github.com/superfly/flyctl/issues/1710
fly secrets import should tolerate trailing comments after a value
**Describe the bug**

The following syntax is tolerated by many local .env readers (e.g. dotenv, python-dotenv), and ignores the trailing comment

SIGNUP_BALANCE_BONUS=50  # amount in peso

But fly secrets import ingests it literally including the comment part, which breaks the application.

Overall, developer's expectation is that if something works locally with the local .env file, and then you run fly secrets import.... Everything should work in the cloud as-is.      If there is any difference in behavior of .env files parsing between common dotenv frameworks (node, python-dotenv, godotenv), choose most popular versuon of behavior between frameworks.

Related issues with fly secrets import:
* https://github.com/superfly/flyctl/issues/589
* https://github.com/superfly/flyctl/issues/3002




Discussion: Hey, did you got any workaround for that?
@thereis no, I was manually removing whitespace prior to running the command. It shouldn't be hard to strip the whitespace on the fly though.
I'm no Go engineer, but maybe someone can add the whitespace stripping [here](https://github.com/superfly/fly-go/blob/main/resource_secrets.go#L5-L42)
And in the meantime, I think this may do. Removes blank lines first then removes whitespace surrounding `=`
```
cat .env | sed -r '/^\s*$/d' | sed -r 's/\s*=\s*/=/g' | flyctl secrets import
```

Wow, thanks for a quick fix. Impressed.



Fix (patch):
diff --git a/internal/command/secrets/parser.go b/internal/command/secrets/parser.go
index 704e312c67..e7195708e4 100644
--- a/internal/command/secrets/parser.go
+++ b/internal/command/secrets/parser.go
@@ -28,24 +28,29 @@ func parseSecrets(reader io.Reader) (map[string]string, error) {
 				continue
 			}
 
-			parts := strings.SplitN(line, "=", 2)
-			if len(parts) != 2 {
+			key, value, ok := strings.Cut(line, "=")
+			if !ok {
 				return nil, fmt.Errorf("Secrets must be provided as NAME=VALUE pairs (%s is invalid)", line)
 			}
+			key = strings.TrimSpace(key)
+			value = strings.TrimLeft(value, " ")
+			l, _, ok := strings.Cut(value, "#")
+			if ok && strings.Count(l, `"`)%2 == 0 {
+				value = strings.TrimRight(l, " ")
+			}
 
-			if strings.HasPrefix(parts[1], `"""`) {
+			if strings.HasPrefix(value, `"""`) {
 				// Switch to multiline
 				parserState = parserStateMultiline
-				parsedKey = parts[0]
-				parsedVal.WriteString(strings.TrimPrefix(parts[1], `"""`))
+				parsedKey = key
+				parsedVal.WriteString(strings.TrimPrefix(value, `"""`))
 				parsedVal.WriteString("\n")
 			} else {
-				value := parts[1]
 				if strings.HasPrefix(value, `"`) && strings.HasSuffix(value, `"`) {
 					// Remove double quotes
 					value = value[1 : len(value)-1]
 				}
-				secrets[parts[0]] = value
+				secrets[key] = value
 			}
 		case parserStateMultiline:
 			if strings.HasSuffix(line, `"""`) {