From dc6500eac68b60e9d2bda5e8b0f26e301eb6ba05 Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 29 Dec 2025 17:02:01 +0700 Subject: [PATCH] Fix repository cloning when running inside a container Use DataDir/builds instead of /tmp for clone directories so that bind mounts work correctly when upaas itself runs in a Docker container. The /tmp directory inside the upaas container isn't accessible to the Docker daemon on the host, causing bind mount failures. Also fix test setups to pass Config to deploy service and add delay to webhook test to avoid temp directory cleanup race with async deployment goroutine. --- internal/handlers/handlers_test.go | 7 +++++++ internal/service/deploy/deploy.go | 15 ++++++++++++++- internal/service/webhook/webhook_test.go | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/internal/handlers/handlers_test.go b/internal/handlers/handlers_test.go index 77e207c..adec558 100644 --- a/internal/handlers/handlers_test.go +++ b/internal/handlers/handlers_test.go @@ -7,6 +7,7 @@ import ( "net/url" "strings" "testing" + "time" "github.com/go-chi/chi/v5" "github.com/stretchr/testify/assert" @@ -115,6 +116,7 @@ func createAppServices( deploySvc, deployErr := deploy.New(fx.Lifecycle(nil), deploy.ServiceParams{ Logger: logInstance, + Config: cfg, Database: dbInstance, Docker: dockerClient, Notify: notifySvc, @@ -484,4 +486,9 @@ func TestHandleWebhookProcessesValidWebhook(t *testing.T) { handler.ServeHTTP(recorder, request) assert.Equal(t, http.StatusOK, recorder.Code) + + // Allow async deployment goroutine to complete before test cleanup. + // The deployment will fail quickly (docker not connected) but we need + // to wait for it to finish to avoid temp directory cleanup race. + time.Sleep(100 * time.Millisecond) } diff --git a/internal/service/deploy/deploy.go b/internal/service/deploy/deploy.go index 79dd333..e72aad9 100644 --- a/internal/service/deploy/deploy.go +++ b/internal/service/deploy/deploy.go @@ -26,6 +26,8 @@ const ( healthCheckDelaySeconds = 60 // upaasLabelCount is the number of upaas-specific labels added to containers. upaasLabelCount = 1 + // buildsDirPermissions is the permission mode for the builds directory. + buildsDirPermissions = 0o750 ) // Sentinel errors for deployment failures. @@ -202,7 +204,18 @@ func (svc *Service) cloneRepository( app *models.App, deployment *models.Deployment, ) (string, func(), error) { - tempDir, err := os.MkdirTemp("", "upaas-"+app.ID+"-*") + // Use a subdirectory of DataDir for builds since it's mounted from the host + // and accessible to Docker for bind mounts (unlike /tmp inside the container) + buildsDir := filepath.Join(svc.config.DataDir, "builds") + + err := os.MkdirAll(buildsDir, buildsDirPermissions) + if err != nil { + svc.failDeployment(ctx, app, deployment, fmt.Errorf("failed to create builds dir: %w", err)) + + return "", nil, fmt.Errorf("failed to create builds dir: %w", err) + } + + tempDir, err := os.MkdirTemp(buildsDir, app.ID+"-*") if err != nil { svc.failDeployment(ctx, app, deployment, fmt.Errorf("failed to create temp dir: %w", err)) diff --git a/internal/service/webhook/webhook_test.go b/internal/service/webhook/webhook_test.go index 3820cb8..90078a9 100644 --- a/internal/service/webhook/webhook_test.go +++ b/internal/service/webhook/webhook_test.go @@ -63,7 +63,7 @@ func setupTestService(t *testing.T) (*webhook.Service, *database.Database, func( require.NoError(t, err) deploySvc, err := deploy.New(fx.Lifecycle(nil), deploy.ServiceParams{ - Logger: deps.logger, Database: deps.db, Docker: dockerClient, Notify: notifySvc, + Logger: deps.logger, Config: deps.config, Database: deps.db, Docker: dockerClient, Notify: notifySvc, }) require.NoError(t, err)