shellEscapeArg escapes a single argument for safe use in shell commands. Arguments containing ${{ }} GitHub Actions expressions are double-quoted; other arguments with special shell characters are single-quoted.
(arg string)
| 27 | // Arguments containing ${{ }} GitHub Actions expressions are double-quoted; |
| 28 | // other arguments with special shell characters are single-quoted. |
| 29 | func shellEscapeArg(arg string) string { |
| 30 | // If the argument contains GitHub Actions expressions (${{ }}), use double-quote |
| 31 | // wrapping. GitHub Actions evaluates ${{ }} at the YAML level before the shell runs, |
| 32 | // so single-quoting would mangle the expression syntax (e.g., 'staging' inside |
| 33 | // ${{ env.X == 'staging' }} becomes '\''staging'\'' which GA cannot parse). |
| 34 | // Double-quoting preserves the expression for GA evaluation. |
| 35 | if containsExpression(arg) { |
| 36 | shellLog.Print("Argument contains GitHub Actions expression, using double-quote wrapping") |
| 37 | escaped := strings.ReplaceAll(arg, `"`, `\"`) |
| 38 | // Escape bare $ signs (those not part of a ${{ }} expression) so that bash |
| 39 | // does not perform variable expansion inside the double-quoted string. |
| 40 | // For example, the JSON key "$schema" must become "\$schema" so bash writes |
| 41 | // the literal dollar sign rather than expanding the (unset) shell variable |
| 42 | // $schema to an empty string. ${{ … }} expressions are left untouched because |
| 43 | // GitHub Actions resolves them before the shell ever runs. |
| 44 | escaped = escapeBareShellDollarSigns(escaped) |
| 45 | return `"` + escaped + `"` |
| 46 | } |
| 47 | |
| 48 | // Check if the argument contains special shell characters that need escaping |
| 49 | if strings.ContainsAny(arg, "()[]{}*?$`\"'\\|&;<> \t\n") { |
| 50 | shellLog.Print("Argument contains special characters, applying escaping") |
| 51 | // Handle single quotes in the argument by escaping them |
| 52 | // Use '\'' instead of '\"'\"' to avoid creating double-quoted contexts |
| 53 | // that would interpret backslash escape sequences |
| 54 | escaped := strings.ReplaceAll(arg, "'", "'\\''") |
| 55 | return "'" + escaped + "'" |
| 56 | } |
| 57 | return arg |
| 58 | } |
| 59 | |
| 60 | // escapeBareShellDollarSigns replaces every $ that is NOT the start of a ${{ }} |
| 61 | // GitHub Actions expression with \$. This prevents bash from performing variable |