@@ -21,6 +21,7 @@ import (
21
21
22
22
"github.com/docker/cli/cli/command"
23
23
"github.com/google/uuid"
24
+
24
25
"github.com/kimdre/doco-cd/internal/config"
25
26
"github.com/kimdre/doco-cd/internal/docker"
26
27
"github.com/kimdre/doco-cd/internal/git"
@@ -46,7 +47,7 @@ func onError(w http.ResponseWriter, log *slog.Logger, errMsg string, details any
46
47
statusCode )
47
48
}
48
49
49
- // getRepoName extracts the repository name from the clone URL
50
+ // getRepoName extracts the repository name from the clone URL.
50
51
func getRepoName (cloneURL string ) string {
51
52
repoName := strings .SplitAfter (cloneURL , "://" )[1 ]
52
53
@@ -57,7 +58,7 @@ func getRepoName(cloneURL string) string {
57
58
return strings .TrimSuffix (repoName , ".git" )
58
59
}
59
60
60
- // HandleEvent handles the incoming webhook event
61
+ // HandleEvent handles the incoming webhook event.
61
62
func HandleEvent (ctx context.Context , jobLog * slog.Logger , w http.ResponseWriter , appConfig * config.AppConfig , dataMountPoint container.MountPoint , payload webhook.ParsedPayload , customTarget , jobID string , dockerCli command.Cli , dockerClient * client.Client ) {
62
63
startTime := time .Now ()
63
64
repoName := getRepoName (payload .CloneURL )
@@ -83,6 +84,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
83
84
84
85
if appConfig .GitAccessToken == "" {
85
86
onError (w , jobLog , "missing access token for private repository" , "" , jobID , http .StatusInternalServerError )
87
+
86
88
return
87
89
}
88
90
@@ -95,18 +97,21 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
95
97
// Validate payload.FullName to prevent directory traversal
96
98
if strings .Contains (payload .FullName , ".." ) {
97
99
onError (w , jobLog .With (slog .String ("repository" , payload .FullName )), "invalid repository name" , "" , jobID , http .StatusBadRequest )
100
+
98
101
return
99
102
}
100
103
101
104
internalRepoPath , err := utils .VerifyAndSanitizePath (filepath .Join (dataMountPoint .Destination , repoName ), dataMountPoint .Destination ) // Path inside the container
102
105
if err != nil {
103
106
onError (w , jobLog .With (logger .ErrAttr (err )), "failed to verify and sanitize internal filesystem path" , err .Error (), jobID , http .StatusBadRequest )
107
+
104
108
return
105
109
}
106
110
107
111
externalRepoPath , err := utils .VerifyAndSanitizePath (filepath .Join (dataMountPoint .Destination , repoName ), dataMountPoint .Destination ) // Path on the host
108
112
if err != nil {
109
113
onError (w , jobLog .With (logger .ErrAttr (err )), "failed to verify and sanitize external filesystem path" , err .Error (), jobID , http .StatusBadRequest )
114
+
110
115
return
111
116
}
112
117
@@ -120,10 +125,12 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
120
125
_ , err = git .UpdateRepository (internalRepoPath , payload .Ref , appConfig .SkipTLSVerification , appConfig .HttpProxy )
121
126
if err != nil {
122
127
onError (w , jobLog .With (logger .ErrAttr (err )), "failed to checkout repository" , err .Error (), jobID , http .StatusInternalServerError )
128
+
123
129
return
124
130
}
125
131
} else {
126
132
onError (w , jobLog .With (logger .ErrAttr (err )), "failed to clone repository" , err .Error (), jobID , http .StatusInternalServerError )
133
+
127
134
return
128
135
}
129
136
} else {
@@ -139,6 +146,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
139
146
jobLog .Warn (err .Error ())
140
147
} else {
141
148
onError (w , jobLog .With (logger .ErrAttr (err )), "failed to get deploy configuration" , err .Error (), jobID , http .StatusInternalServerError )
149
+
142
150
return
143
151
}
144
152
}
@@ -154,12 +162,14 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
154
162
internalRepoPath , err = utils .VerifyAndSanitizePath (filepath .Join (dataMountPoint .Destination , repoName ), dataMountPoint .Destination ) // Path inside the container
155
163
if err != nil {
156
164
onError (w , subJobLog .With (logger .ErrAttr (err )), "invalid repository name" , err .Error (), jobID , http .StatusBadRequest )
165
+
157
166
return
158
167
}
159
168
160
169
externalRepoPath , err = utils .VerifyAndSanitizePath (filepath .Join (dataMountPoint .Source , repoName ), dataMountPoint .Source ) // Path on the host
161
170
if err != nil {
162
171
onError (w , subJobLog .With (logger .ErrAttr (err )), "invalid repository name" , err .Error (), jobID , http .StatusBadRequest )
172
+
163
173
return
164
174
}
165
175
@@ -182,6 +192,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
182
192
_ , err = git .CloneRepository (internalRepoPath , cloneUrl , deployConfig .Reference , appConfig .SkipTLSVerification , appConfig .HttpProxy )
183
193
if err != nil && ! errors .Is (err , git .ErrRepositoryAlreadyExists ) {
184
194
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to clone remote repository" , err .Error (), jobID , http .StatusInternalServerError )
195
+
185
196
return
186
197
}
187
198
@@ -193,12 +204,14 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
193
204
repo , err := git .UpdateRepository (internalRepoPath , deployConfig .Reference , appConfig .SkipTLSVerification , appConfig .HttpProxy )
194
205
if err != nil {
195
206
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to checkout repository" , err .Error (), jobID , http .StatusInternalServerError )
207
+
196
208
return
197
209
}
198
210
199
211
latestCommit , err := git .GetLatestCommit (repo , deployConfig .Reference )
200
212
if err != nil {
201
213
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to get latest commit" , err .Error (), jobID , http .StatusInternalServerError )
214
+
202
215
return
203
216
}
204
217
@@ -209,12 +222,14 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
209
222
containers , err := docker .GetLabeledContainers (ctx , dockerClient , api .ProjectLabel , deployConfig .Name )
210
223
if err != nil {
211
224
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to retrieve containers" , err .Error (), jobID , http .StatusInternalServerError )
225
+
212
226
return
213
227
}
214
228
215
229
// If no containers are found, skip the destruction step
216
230
if len (containers ) == 0 {
217
231
subJobLog .Debug ("no containers found for stack, skipping..." )
232
+
218
233
continue
219
234
}
220
235
@@ -251,6 +266,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
251
266
err = docker .DestroyStack (subJobLog , & ctx , & dockerCli , deployConfig )
252
267
if err != nil {
253
268
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to destroy stack" , err .Error (), jobID , http .StatusInternalServerError )
269
+
254
270
return
255
271
}
256
272
@@ -263,6 +279,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
263
279
subDirs , err := os .ReadDir (parentDir )
264
280
if err != nil {
265
281
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to read parent directory" , err .Error (), jobID , http .StatusInternalServerError )
282
+
266
283
return
267
284
}
268
285
@@ -274,13 +291,15 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
274
291
err = os .RemoveAll (internalRepoPath )
275
292
if err != nil {
276
293
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to remove deployment directory" , err .Error (), jobID , http .StatusInternalServerError )
294
+
277
295
return
278
296
}
279
297
} else {
280
298
// Remove the parent directory if it has only one subdirectory
281
299
err = os .RemoveAll (parentDir )
282
300
if err != nil {
283
301
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to remove deployment directory" , err .Error (), jobID , http .StatusInternalServerError )
302
+
284
303
return
285
304
}
286
305
@@ -292,6 +311,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
292
311
containers , err := docker .GetLabeledContainers (ctx , dockerClient , api .ProjectLabel , deployConfig .Name )
293
312
if err != nil {
294
313
onError (w , subJobLog .With (logger .ErrAttr (err )), "failed to retrieve containers" , err .Error (), jobID , http .StatusInternalServerError )
314
+
295
315
return
296
316
}
297
317
@@ -303,6 +323,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
303
323
name , ok := cont .Labels [docker .DocoCDLabels .Repository .Name ]
304
324
if ! ok || name != payload .FullName {
305
325
correctRepo = false
326
+
306
327
break
307
328
}
308
329
@@ -343,6 +364,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
343
364
err = docker .DeployStack (subJobLog , internalRepoPath , externalRepoPath , & ctx , & dockerCli , & payload , deployConfig , latestCommit , Version , false )
344
365
if err != nil {
345
366
onError (w , subJobLog .With (logger .ErrAttr (err )), "deployment failed" , err .Error (), jobID , http .StatusInternalServerError )
367
+
346
368
return
347
369
}
348
370
}
@@ -355,7 +377,7 @@ func HandleEvent(ctx context.Context, jobLog *slog.Logger, w http.ResponseWriter
355
377
}
356
378
357
379
func (h * handlerData ) WebhookHandler (w http.ResponseWriter , r * http.Request ) {
358
- ctx := context . Background ()
380
+ ctx := r . Context ()
359
381
360
382
customTarget := r .PathValue ("customTarget" )
361
383
@@ -405,6 +427,7 @@ func (h *handlerData) HealthCheckHandler(w http.ResponseWriter, _ *http.Request)
405
427
err := docker .VerifySocketConnection ()
406
428
if err != nil {
407
429
onError (w , h .log .With (logger .ErrAttr (err )), docker .ErrDockerSocketConnectionFailed .Error (), err .Error (), "" , http .StatusServiceUnavailable )
430
+
408
431
return
409
432
}
410
433
0 commit comments