Skip to content

fix(env): single-quote exported values in every product tree - #19

Merged
hectorvent merged 1 commit into
mainfrom
fix/env-shell-quoting
Aug 27, 2026
Merged

fix(env): single-quote exported values in every product tree#19
hectorvent merged 1 commit into
mainfrom
fix/env-shell-quoting

Conversation

@hectorvent

Copy link
Copy Markdown
Contributor

Summary

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. 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) and GcpEnvCommand carried a byte-identical copy of the same emitter — their values are ;-free URLs today, so nobody had hit it, but --host/--account/--region/--endpoint and the FLOCI_* env vars all feed straight into eval input:

case "fish"              -> "set -x " + key + " \"" + value + "\"";   // double quotes, no escaping
case "powershell", "ps1" -> "$env:" + key + " = \"" + value + "\"";   // double quotes, no escaping
default                  -> "export " + key + "=" + value;            // no quoting at all

floci oci env already solved this in #15 (its TF_VAR_CLIENT_HOST_OVERRIDES is also ;-separated). The copy-drift survived the #16 ProductProfile unification because the four env commands 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.ShellExport and 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 through eval.

Also fixed: AwsCliEndpointCheck and AzCliConnectionStringCheck printed Fix: 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:

$ floci az env
-export AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;...
+export AZURE_STORAGE_CONNECTION_STRING='DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;...'

Closes #18

Type of change

  • Bug fix (fix:)
  • New feature (feat:)
  • Breaking change (feat!: or fix!:)
  • Docs / chore

Product trees affected

  • AWS (root tree)
  • GCP (commands/gcp/)
  • Azure (commands/az/)
  • OCI (commands/oci/) — refactored to the shared helper, behavior unchanged

Verification

  • mvn test — 67 tests pass.
  • eval $(floci az env) now sets the full 356-char connection string (previously just DefaultEndpointsProtocol=http); floci env, floci gcp env, floci oci env all still round-trip through eval.
  • All three --shell modes exercised; -o json output is unchanged (raw values, no quoting — correct).
  • Adversarial check — floci az env --host 'x$(touch /tmp/pwned)\id`'"'"'; echo PWNED'` prints the payload inert, executes nothing, creates no file.
  • floci doctor / floci az doctor hints verified copy-pasteable.

Checklist

  • mvn test passes locally
  • New or updated tests added — OciEnvFormatTestShellExportTest, keeping its four assertions (now covering all four trees) and adding the connection-string regression from the issue
  • CHANGELOG.md entry added under [Unreleased]
  • README.md updated — one line in the floci az env section noting the value is single-quoted and safe to eval (no literal export output is printed anywhere in the README, so nothing was invalidated)
  • Native binary — N/A, no Jackson serialization or dependency changes; ShellExport is a plain static utility needing no reflect-config.json entry
  • Commit messages / PR title follow Conventional Commits

Out of scope

  • --shell still silently falls through to the bash branch for unrecognized values (no validation) — pre-existing, separate concern.
  • No new flags (--unset, etc.).

`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
@greptile-apps

greptile-apps Bot commented Aug 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR centralizes shell export rendering in ShellExport, safely single-quotes environment values for Bash, fish, and PowerShell, and applies the helper across all product trees and relevant doctor hints.

  • Fixes Azure connection strings containing semicolons when evaluated by a shell.
  • Replaces duplicated environment emitters in AWS, Azure, GCP, and OCI commands.
  • Makes AWS and Azure doctor suggestions safely copyable in Bash.
  • Adds regression and adversarial escaping coverage plus documentation updates.

Confidence Score: 5/5

The PR appears safe to merge; no actionable correctness or security defects were identified in the shared escaping implementation or its integrations.

The shared helper preserves values under each supported shell’s quoting rules, all four environment commands consistently use it, structured output remains unchanged, and the regression tests cover the vulnerable Azure connection-string path and hostile shell characters.

Important Files Changed

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

@hectorvent
hectorvent merged commit 6496795 into main Aug 27, 2026
3 checks passed
@hectorvent

Copy link
Copy Markdown
Contributor Author

🎉 This PR is included in version 0.2.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The floci az env connection string should be quoted

1 participant