From fd995680ea3bedba8e69fff4d3caee4627212c8a Mon Sep 17 00:00:00 2001 From: Jakub Domeracki Date: Tue, 2 Jun 2026 12:40:53 +0000 Subject: [PATCH] fix(coder-labs/gemini): base64-encode task prompt to handle special characters Encode task_prompt before passing it into the start script and decode it in start.sh, matching how the system prompt is already handled. This ensures prompts containing single quotes or other shell metacharacters are passed through correctly instead of breaking the start script. Adds a regression test and bumps the module to v3.0.2. --- registry/coder-labs/modules/gemini/README.md | 8 +++--- .../coder-labs/modules/gemini/main.test.ts | 28 +++++++++++++++++++ registry/coder-labs/modules/gemini/main.tf | 2 +- .../modules/gemini/scripts/start.sh | 7 +++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/registry/coder-labs/modules/gemini/README.md b/registry/coder-labs/modules/gemini/README.md index 57842ac6..f625a118 100644 --- a/registry/coder-labs/modules/gemini/README.md +++ b/registry/coder-labs/modules/gemini/README.md @@ -13,7 +13,7 @@ Run [Gemini CLI](https://github.com/google-gemini/gemini-cli) in your workspace ```tf module "gemini" { source = "registry.coder.com/coder-labs/gemini/coder" - version = "3.0.1" + version = "3.0.2" agent_id = coder_agent.main.id folder = "/home/coder/project" } @@ -46,7 +46,7 @@ variable "gemini_api_key" { module "gemini" { source = "registry.coder.com/coder-labs/gemini/coder" - version = "3.0.1" + version = "3.0.2" agent_id = coder_agent.main.id gemini_api_key = var.gemini_api_key folder = "/home/coder/project" @@ -94,7 +94,7 @@ data "coder_parameter" "ai_prompt" { module "gemini" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/gemini/coder" - version = "3.0.1" + version = "3.0.2" agent_id = coder_agent.main.id gemini_api_key = var.gemini_api_key gemini_model = "gemini-2.5-flash" @@ -134,7 +134,7 @@ For enterprise users who prefer Google's Vertex AI platform: ```tf module "gemini" { source = "registry.coder.com/coder-labs/gemini/coder" - version = "3.0.1" + version = "3.0.2" agent_id = coder_agent.main.id gemini_api_key = var.gemini_api_key folder = "/home/coder/project" diff --git a/registry/coder-labs/modules/gemini/main.test.ts b/registry/coder-labs/modules/gemini/main.test.ts index 0680ce35..04ed11c6 100644 --- a/registry/coder-labs/modules/gemini/main.test.ts +++ b/registry/coder-labs/modules/gemini/main.test.ts @@ -263,6 +263,34 @@ describe("gemini", async () => { expect(resp).toContain("Running automated task:"); }); + test("task-prompt-with-special-characters", async () => { + // A single quote in the prompt previously broke shell quoting in the start + // script. The prompt must be passed through verbatim and never interpreted + // by the shell. + const taskPrompt = `dummy prompt' ; touch /tmp/task-prompt-marker ; echo '`; + const { id } = await setup({ + moduleVariables: { + task_prompt: taskPrompt, + }, + }); + await execModuleScript(id); + + // No part of the prompt should be executed by the shell. + const marker = await execContainer(id, [ + "bash", + "-c", + "test -e /tmp/task-prompt-marker && echo CREATED || echo SAFE", + ]); + expect(marker.stdout).toContain("SAFE"); + + // The prompt must be passed through verbatim, including the single quotes. + const promptFile = await readFileContainer( + id, + "/home/coder/.gemini-module/prompt.txt", + ); + expect(promptFile).toContain(taskPrompt); + }); + test("start-without-prompt", async () => { const { id } = await setup(); await execModuleScript(id); diff --git a/registry/coder-labs/modules/gemini/main.tf b/registry/coder-labs/modules/gemini/main.tf index 336c112f..3dfd1774 100644 --- a/registry/coder-labs/modules/gemini/main.tf +++ b/registry/coder-labs/modules/gemini/main.tf @@ -216,7 +216,7 @@ module "agentapi" { GEMINI_YOLO_MODE='${var.enable_yolo_mode}' \ GEMINI_MODEL='${var.gemini_model}' \ GEMINI_START_DIRECTORY='${var.folder}' \ - GEMINI_TASK_PROMPT='${var.task_prompt}' \ + GEMINI_TASK_PROMPT='${base64encode(var.task_prompt)}' \ /tmp/start.sh EOT } diff --git a/registry/coder-labs/modules/gemini/scripts/start.sh b/registry/coder-labs/modules/gemini/scripts/start.sh index eed55090..d3204312 100644 --- a/registry/coder-labs/modules/gemini/scripts/start.sh +++ b/registry/coder-labs/modules/gemini/scripts/start.sh @@ -44,6 +44,13 @@ else } fi +# The task prompt is base64-encoded in main.tf so prompts containing single +# quotes or other shell metacharacters do not break the start script. Decode +# it before use. +if [ -n "${GEMINI_TASK_PROMPT:-}" ]; then + GEMINI_TASK_PROMPT=$(echo -n "$GEMINI_TASK_PROMPT" | base64 -d) +fi + if [ -n "$GEMINI_TASK_PROMPT" ]; then printf "Running automated task: %s\n" "$GEMINI_TASK_PROMPT" PROMPT="Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GEMINI_TASK_PROMPT"