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.
This commit is contained in:
Jakub Domeracki
2026-06-02 12:40:53 +00:00
parent 358ca6804b
commit fd995680ea
4 changed files with 40 additions and 5 deletions
+4 -4
View File
@@ -13,7 +13,7 @@ Run [Gemini CLI](https://github.com/google-gemini/gemini-cli) in your workspace
```tf ```tf
module "gemini" { module "gemini" {
source = "registry.coder.com/coder-labs/gemini/coder" source = "registry.coder.com/coder-labs/gemini/coder"
version = "3.0.1" version = "3.0.2"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
folder = "/home/coder/project" folder = "/home/coder/project"
} }
@@ -46,7 +46,7 @@ variable "gemini_api_key" {
module "gemini" { module "gemini" {
source = "registry.coder.com/coder-labs/gemini/coder" source = "registry.coder.com/coder-labs/gemini/coder"
version = "3.0.1" version = "3.0.2"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
gemini_api_key = var.gemini_api_key gemini_api_key = var.gemini_api_key
folder = "/home/coder/project" folder = "/home/coder/project"
@@ -94,7 +94,7 @@ data "coder_parameter" "ai_prompt" {
module "gemini" { module "gemini" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder-labs/gemini/coder" source = "registry.coder.com/coder-labs/gemini/coder"
version = "3.0.1" version = "3.0.2"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
gemini_api_key = var.gemini_api_key gemini_api_key = var.gemini_api_key
gemini_model = "gemini-2.5-flash" gemini_model = "gemini-2.5-flash"
@@ -134,7 +134,7 @@ For enterprise users who prefer Google's Vertex AI platform:
```tf ```tf
module "gemini" { module "gemini" {
source = "registry.coder.com/coder-labs/gemini/coder" source = "registry.coder.com/coder-labs/gemini/coder"
version = "3.0.1" version = "3.0.2"
agent_id = coder_agent.main.id agent_id = coder_agent.main.id
gemini_api_key = var.gemini_api_key gemini_api_key = var.gemini_api_key
folder = "/home/coder/project" folder = "/home/coder/project"
@@ -263,6 +263,34 @@ describe("gemini", async () => {
expect(resp).toContain("Running automated task:"); 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 () => { test("start-without-prompt", async () => {
const { id } = await setup(); const { id } = await setup();
await execModuleScript(id); await execModuleScript(id);
+1 -1
View File
@@ -216,7 +216,7 @@ module "agentapi" {
GEMINI_YOLO_MODE='${var.enable_yolo_mode}' \ GEMINI_YOLO_MODE='${var.enable_yolo_mode}' \
GEMINI_MODEL='${var.gemini_model}' \ GEMINI_MODEL='${var.gemini_model}' \
GEMINI_START_DIRECTORY='${var.folder}' \ GEMINI_START_DIRECTORY='${var.folder}' \
GEMINI_TASK_PROMPT='${var.task_prompt}' \ GEMINI_TASK_PROMPT='${base64encode(var.task_prompt)}' \
/tmp/start.sh /tmp/start.sh
EOT EOT
} }
@@ -44,6 +44,13 @@ else
} }
fi 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 if [ -n "$GEMINI_TASK_PROMPT" ]; then
printf "Running automated task: %s\n" "$GEMINI_TASK_PROMPT" 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" PROMPT="Every step of the way, report tasks to Coder with proper descriptions and statuses. Your task at hand: $GEMINI_TASK_PROMPT"