fix(git-clone): use unique temp file for post_clone_script to avoid race condition (#601)

## Summary

Fixes a race condition when multiple `git-clone` modules with
`post_clone_script` run concurrently.

## Problem

All instances of the git-clone module use the same hardcoded
`/tmp/post_clone.sh` path. When multiple modules run concurrently (or
overlap), they collide on the same temp file, causing:

```
rm: cannot remove '/tmp/post_clone.sh': No such file or directory
```

This results in a non-zero exit code, causing the workspace to appear
unhealthy.

## Solution

Use `mktemp` to generate a unique temporary filename for each module
instance:

```bash
POST_CLONE_TMP=$(mktemp /tmp/post_clone_XXXXXX.sh)
```

This ensures each concurrent execution uses its own temp file,
eliminating the race condition.

Fixes #600

---------

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
Co-authored-by: Matyas Danter <mdanter@gmail.com>
This commit is contained in:
blinkagent[bot] 2025-12-15 11:19:11 -06:00 committed by GitHub
parent bda3eb96e8
commit ab6799ac07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 21 additions and 16 deletions

View File

@ -14,7 +14,7 @@ This module allows you to automatically clone a repository by URL and skip if it
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://github.com/coder/coder" url = "https://github.com/coder/coder"
} }
@ -28,7 +28,7 @@ module "git-clone" {
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://github.com/coder/coder" url = "https://github.com/coder/coder"
base_dir = "~/projects/coder" base_dir = "~/projects/coder"
@ -43,11 +43,12 @@ To use with [Git Authentication](https://coder.com/docs/v2/latest/admin/git-prov
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://github.com/coder/coder" url = "https://github.com/coder/coder"
} }
data "coder_external_auth" "github" { data "coder_external_auth" "github" {
id = "github" id = "github"
} }
@ -69,11 +70,12 @@ data "coder_parameter" "git_repo" {
module "git_clone" { module "git_clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = data.coder_parameter.git_repo.value url = data.coder_parameter.git_repo.value
} }
# Create a code-server instance for the cloned repository # Create a code-server instance for the cloned repository
module "code-server" { module "code-server" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
@ -103,13 +105,14 @@ Configuring `git-clone` for a self-hosted GitHub Enterprise Server running at `g
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://github.example.com/coder/coder/tree/feat/example" url = "https://github.example.com/coder/coder/tree/feat/example"
git_providers = { git_providers = {
"https://github.example.com/" = { "https://github.example.com/" = {
provider = "github" provider = "github"
} }
} }
} }
``` ```
@ -122,7 +125,7 @@ To GitLab clone with a specific branch like `feat/example`
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://gitlab.com/coder/coder/-/tree/feat/example" url = "https://gitlab.com/coder/coder/-/tree/feat/example"
} }
@ -134,13 +137,14 @@ Configuring `git-clone` for a self-hosted GitLab running at `gitlab.example.com`
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://gitlab.example.com/coder/coder/-/tree/feat/example" url = "https://gitlab.example.com/coder/coder/-/tree/feat/example"
git_providers = { git_providers = {
"https://gitlab.example.com/" = { "https://gitlab.example.com/" = {
provider = "gitlab" provider = "gitlab"
} }
} }
} }
``` ```
@ -155,7 +159,7 @@ For example, to clone the `feat/example` branch:
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://github.com/coder/coder" url = "https://github.com/coder/coder"
branch_name = "feat/example" branch_name = "feat/example"
@ -173,7 +177,7 @@ For example, this will clone into the `~/projects/coder/coder-dev` folder:
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://github.com/coder/coder" url = "https://github.com/coder/coder"
folder_name = "coder-dev" folder_name = "coder-dev"
@ -191,8 +195,8 @@ If not defined, the default, `0`, performs a full clone.
```tf ```tf
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://github.com/coder/coder" url = "https://github.com/coder/coder"
depth = 1 depth = 1
@ -208,7 +212,7 @@ This is useful for running initialization tasks like installing dependencies or
module "git-clone" { module "git-clone" {
count = data.coder_workspace.me.start_count count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder" source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.2" version = "1.2.3"
agent_id = coder_agent.example.id agent_id = coder_agent.example.id
url = "https://github.com/coder/coder" url = "https://github.com/coder/coder"
post_clone_script = <<-EOT post_clone_script = <<-EOT

View File

@ -58,9 +58,10 @@ fi
# Run post-clone script if provided # Run post-clone script if provided
if [ -n "$POST_CLONE_SCRIPT" ]; then if [ -n "$POST_CLONE_SCRIPT" ]; then
echo "Running post-clone script..." echo "Running post-clone script..."
echo "$POST_CLONE_SCRIPT" | base64 -d > /tmp/post_clone.sh POST_CLONE_TMP=$(mktemp)
chmod +x /tmp/post_clone.sh echo "$POST_CLONE_SCRIPT" | base64 -d > "$POST_CLONE_TMP"
chmod +x "$POST_CLONE_TMP"
cd "$CLONE_PATH" || exit cd "$CLONE_PATH" || exit
/tmp/post_clone.sh $POST_CLONE_TMP
rm /tmp/post_clone.sh rm "$POST_CLONE_TMP"
fi fi