fix(env): single-quote exported values in every product tree - #19
Conversation
`floci az env` printed the semicolon-separated Azure connection string unquoted, so `eval $(floci az env)` set only AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=http and ran the remaining segments as commands — `az` then reported "Invalid connection string". `floci env` and `floci gcp env` carried a byte-identical copy of the same unquoted emitter (their values are `;`-free URLs today, so nobody hit it), and the aws.cli.endpoint / az.cli.connection-string doctor checks suggested export lines with the same flaw. Extract the correct emitter that `floci oci env` already had into io.floci.cli.output.ShellExport and use it everywhere: values are single quoted with per-shell escaping for bash, fish, and PowerShell, so `;`, `$`, backticks, and quotes can neither break nor inject through `eval`. OciEnvFormatTest becomes ShellExportTest, keeping its four assertions and adding the connection-string regression from the issue. Closes #18
|
| Filename | Overview |
|---|---|
| src/main/java/io/floci/cli/output/ShellExport.java | Introduces correct per-shell single-quote escaping for POSIX shells, fish, and PowerShell. |
| src/main/java/io/floci/cli/commands/az/AzEnvCommand.java | Routes connection-string and SDK-variable output through the safe shared emitter. |
| src/main/java/io/floci/cli/commands/EnvCommand.java | Replaces the AWS tree's unquoted emitter with shared safe rendering. |
| src/main/java/io/floci/cli/commands/gcp/GcpEnvCommand.java | Replaces duplicated GCP shell formatting with the shared implementation. |
| src/main/java/io/floci/cli/commands/oci/OciEnvCommand.java | Preserves OCI's existing safe behavior while moving it into the shared helper. |
| src/main/java/io/floci/cli/doctor/checks/AwsCliEndpointCheck.java | Safely quotes Bash export suggestions for current and corrected AWS endpoints. |
| src/main/java/io/floci/cli/doctor/checks/AzCliConnectionStringCheck.java | Safely quotes semicolon-delimited Azure connection-string suggestions. |
| src/test/java/io/floci/cli/unit/ShellExportTest.java | Covers semicolon preservation and quote, backslash, interpolation, and command-substitution escaping across supported shells. |
Reviews (1): Last reviewed commit: "fix(env): single-quote exported values i..." | Re-trigger Greptile
|
🎉 This PR is included in version 0.2.1 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
floci az envprinted the semicolon-separated Azure connection string unquoted, soeval $(floci az env)set onlyAZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=httpand ran the remaining segments as commands —azthen reportedInvalid connection string. This is the documented way to connect to Floci Azure (README quick start), so the primary Azure workflow was broken.The bug was not Azure-specific.
EnvCommand(AWS) andGcpEnvCommandcarried a byte-identical copy of the same emitter — their values are;-free URLs today, so nobody had hit it, but--host/--account/--region/--endpointand theFLOCI_*env vars all feed straight intoevalinput:floci oci envalready solved this in #15 (itsTF_VAR_CLIENT_HOST_OVERRIDESis also;-separated). The copy-drift survived the #16ProductProfileunification because the fourenvcommands are the one genuinely product-specific family and are not subclasses of each other.This PR extracts OCI's correct emitter into
io.floci.cli.output.ShellExportand points all four trees at it — values are single-quoted with per-shell escaping (POSIX'\'', fish\\then\', PowerShell''), so;,$, backticks, and quotes can neither break nor inject througheval.Also fixed:
AwsCliEndpointCheckandAzCliConnectionStringCheckprintedFix: export ...hints with the same flaw (unquoted and double-quoted respectively). They now render through the same helper, so the suggested line is copy-pasteable.Before / after:
Closes #18
Type of change
fix:)feat:)feat!:orfix!:)Product trees affected
commands/gcp/)commands/az/)commands/oci/) — refactored to the shared helper, behavior unchangedVerification
mvn test— 67 tests pass.eval $(floci az env)now sets the full 356-char connection string (previously justDefaultEndpointsProtocol=http);floci env,floci gcp env,floci oci envall still round-trip througheval.--shellmodes exercised;-o jsonoutput is unchanged (raw values, no quoting — correct).floci az env --host 'x$(touch /tmp/pwned)\id`'"'"'; echo PWNED'` prints the payload inert, executes nothing, creates no file.floci doctor/floci az doctorhints verified copy-pasteable.Checklist
mvn testpasses locallyOciEnvFormatTest→ShellExportTest, keeping its four assertions (now covering all four trees) and adding the connection-string regression from the issueCHANGELOG.mdentry added under[Unreleased]README.mdupdated — one line in thefloci az envsection noting the value is single-quoted and safe toeval(no literalexportoutput is printed anywhere in the README, so nothing was invalidated)ShellExportis a plain static utility needing noreflect-config.jsonentryOut of scope
--shellstill silently falls through to the bash branch for unrecognized values (no validation) — pre-existing, separate concern.--unset, etc.).