Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions registry/coder-labs/modules/gemini/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
28 changes: 28 additions & 0 deletions registry/coder-labs/modules/gemini/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion registry/coder-labs/modules/gemini/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
7 changes: 7 additions & 0 deletions registry/coder-labs/modules/gemini/scripts/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading