@@ -20,6 +20,7 @@ import (
20
20
"bytes"
21
21
"context"
22
22
"fmt"
23
+ "io"
23
24
"os"
24
25
"path/filepath"
25
26
"strings"
@@ -280,3 +281,114 @@ services:
280
281
normalizeSpaces (actualOutput ),
281
282
"\n Expected:\n %s\n Got:\n %s" , expected , actualOutput )
282
283
}
284
+
285
+ func TestConfirmRemoteIncludes (t * testing.T ) {
286
+ ctrl := gomock .NewController (t )
287
+ defer ctrl .Finish ()
288
+ cli := mocks .NewMockCli (ctrl )
289
+
290
+ tests := []struct {
291
+ name string
292
+ opts buildOptions
293
+ assumeYes bool
294
+ userInput string
295
+ wantErr bool
296
+ errMessage string
297
+ wantPrompt bool
298
+ wantOutput string
299
+ }{
300
+ {
301
+ name : "no remote includes" ,
302
+ opts : buildOptions {
303
+ ProjectOptions : & ProjectOptions {
304
+ ConfigPaths : []string {
305
+ "docker-compose.yaml" ,
306
+ "./local/path/compose.yaml" ,
307
+ },
308
+ },
309
+ },
310
+ assumeYes : false ,
311
+ wantErr : false ,
312
+ wantPrompt : false ,
313
+ },
314
+ {
315
+ name : "assume yes with remote includes" ,
316
+ opts : buildOptions {
317
+ ProjectOptions : & ProjectOptions {
318
+ ConfigPaths : []string {
319
+ "oci://registry.example.com/stack:latest" ,
320
+ "git://github.com/user/repo.git" ,
321
+ },
322
+ },
323
+ },
324
+ assumeYes : true ,
325
+ wantErr : false ,
326
+ wantPrompt : false ,
327
+ },
328
+ {
329
+ name : "user confirms remote includes" ,
330
+ opts : buildOptions {
331
+ ProjectOptions : & ProjectOptions {
332
+ ConfigPaths : []string {
333
+ "oci://registry.example.com/stack:latest" ,
334
+ "git://github.com/user/repo.git" ,
335
+ },
336
+ },
337
+ },
338
+ assumeYes : false ,
339
+ userInput : "y\n " ,
340
+ wantErr : false ,
341
+ wantPrompt : true ,
342
+ wantOutput : "\n Warning: This Compose project includes files from remote sources:\n " +
343
+ " - oci://registry.example.com/stack:latest\n " +
344
+ " - git://github.com/user/repo.git\n " +
345
+ "\n Remote includes could potentially be malicious. Make sure you trust the source.\n " +
346
+ "Do you want to continue? [y/N]: " ,
347
+ },
348
+ {
349
+ name : "user rejects remote includes" ,
350
+ opts : buildOptions {
351
+ ProjectOptions : & ProjectOptions {
352
+ ConfigPaths : []string {
353
+ "oci://registry.example.com/stack:latest" ,
354
+ },
355
+ },
356
+ },
357
+ assumeYes : false ,
358
+ userInput : "n\n " ,
359
+ wantErr : true ,
360
+ errMessage : "operation cancelled by user" ,
361
+ wantPrompt : true ,
362
+ wantOutput : "\n Warning: This Compose project includes files from remote sources:\n " +
363
+ " - oci://registry.example.com/stack:latest\n " +
364
+ "\n Remote includes could potentially be malicious. Make sure you trust the source.\n " +
365
+ "Do you want to continue? [y/N]: " ,
366
+ },
367
+ }
368
+
369
+ buf := new (bytes.Buffer )
370
+ for _ , tt := range tests {
371
+ t .Run (tt .name , func (t * testing.T ) {
372
+ cli .EXPECT ().Out ().Return (streams .NewOut (buf )).AnyTimes ()
373
+
374
+ if tt .wantPrompt {
375
+ inbuf := io .NopCloser (bytes .NewBufferString (tt .userInput ))
376
+ cli .EXPECT ().In ().Return (streams .NewIn (inbuf )).AnyTimes ()
377
+ }
378
+
379
+ err := confirmRemoteIncludes (cli , tt .opts , tt .assumeYes )
380
+
381
+ if tt .wantErr {
382
+ require .Error (t , err )
383
+ require .Equal (t , tt .errMessage , err .Error ())
384
+ } else {
385
+ require .NoError (t , err )
386
+ }
387
+
388
+ if tt .wantOutput != "" {
389
+ require .Equal (t , tt .wantOutput , buf .String ())
390
+ }
391
+ buf .Reset ()
392
+ })
393
+ }
394
+ }
0 commit comments