Skip to content

Commit 76138b0

Browse files
authored
Merge branch 'main' into 74-git-submodule-support
2 parents cb11759 + d0caa21 commit 76138b0

8 files changed

Lines changed: 136 additions & 44 deletions

File tree

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ The easiest way to get started is by running the `envbuilder` Docker container t
2525
> - The `/tmp/envbuilder` directory persists demo data between commands. You can choose a different directory if needed.
2626
> - To clone a different branch, you append it to `ENVBUILDER_GIT_URL` in the form `#refs/heads/my-branch`. For example: `https://github.com/coder/envbuilder-starter-devcontainer#refs/heads/boring-prompt`.
2727
```bash
28-
docker run -it --rm
29-
-v /tmp/envbuilder:/workspaces
30-
-e ENVBUILDER_GIT_URL=https://github.com/coder/envbuilder-starter-devcontainer
31-
-e ENVBUILDER_INIT_SCRIPT=bash
28+
docker run -it --rm \
29+
-v /tmp/envbuilder:/workspaces \
30+
-e ENVBUILDER_GIT_URL=https://github.com/coder/envbuilder-starter-devcontainer \
31+
-e ENVBUILDER_INIT_SCRIPT=bash \
3232
ghcr.io/coder/envbuilder
3333
```
3434

@@ -77,9 +77,9 @@ else
7777
fi
7878

7979
# Run envbuilder with the setup script
80-
docker run -it --rm
81-
-v ./:/some-dir
82-
-e ENVBUILDER_SETUP_SCRIPT=/some-dir/init.sh
80+
docker run -it --rm \
81+
-v ./:/some-dir \
82+
-e ENVBUILDER_SETUP_SCRIPT=/some-dir/init.sh \
8383
...
8484
```
8585

devcontainer/devcontainer_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424

2525
const workingDir = "/.envbuilder"
2626

27+
var emptyRemoteOpts []remote.Option
28+
2729
func stubLookupEnv(string) (string, bool) {
2830
return "", false
2931
}
@@ -46,7 +48,7 @@ func TestParse(t *testing.T) {
4648
func TestCompileWithFeatures(t *testing.T) {
4749
t.Parallel()
4850
registry := registrytest.New(t)
49-
featureOne := registrytest.WriteContainer(t, registry, "coder/one:tomato", features.TarLayerMediaType, map[string]any{
51+
featureOne := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/one:tomato", features.TarLayerMediaType, map[string]any{
5052
"install.sh": "hey",
5153
"devcontainer-feature.json": features.Spec{
5254
ID: "rust",
@@ -58,7 +60,7 @@ func TestCompileWithFeatures(t *testing.T) {
5860
},
5961
},
6062
})
61-
featureTwo := registrytest.WriteContainer(t, registry, "coder/two:potato", features.TarLayerMediaType, map[string]any{
63+
featureTwo := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/two:potato", features.TarLayerMediaType, map[string]any{
6264
"install.sh": "hey",
6365
"devcontainer-feature.json": features.Spec{
6466
ID: "go",

devcontainer/features/features.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"strconv"
1414
"strings"
1515

16+
"github.com/GoogleContainerTools/kaniko/pkg/creds"
1617
"github.com/go-git/go-billy/v5"
1718
"github.com/google/go-containerregistry/pkg/name"
1819
"github.com/google/go-containerregistry/pkg/v1/remote"
@@ -25,7 +26,7 @@ func extractFromImage(fs billy.Filesystem, directory, reference string) error {
2526
if err != nil {
2627
return fmt.Errorf("parse feature ref %s: %w", reference, err)
2728
}
28-
image, err := remote.Image(ref)
29+
image, err := remote.Image(ref, remote.WithAuthFromKeychain(creds.GetKeychain()))
2930
if err != nil {
3031
return fmt.Errorf("fetch feature image %s: %w", reference, err)
3132
}

devcontainer/features/features_test.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,26 @@ import (
77
"github.com/coder/envbuilder/devcontainer/features"
88
"github.com/coder/envbuilder/testutil/registrytest"
99
"github.com/go-git/go-billy/v5/memfs"
10+
"github.com/google/go-containerregistry/pkg/v1/remote"
1011
"github.com/stretchr/testify/require"
1112
)
1213

14+
var emptyRemoteOpts []remote.Option
15+
1316
func TestExtract(t *testing.T) {
1417
t.Parallel()
1518
t.Run("MissingMediaType", func(t *testing.T) {
1619
t.Parallel()
1720
registry := registrytest.New(t)
18-
ref := registrytest.WriteContainer(t, registry, "coder/test:latest", "some/type", nil)
21+
ref := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/test:latest", "some/type", nil)
1922
fs := memfs.New()
2023
_, err := features.Extract(fs, "", "/", ref)
2124
require.ErrorContains(t, err, "no tar layer found")
2225
})
2326
t.Run("MissingInstallScript", func(t *testing.T) {
2427
t.Parallel()
2528
registry := registrytest.New(t)
26-
ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{
29+
ref := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/test:latest", features.TarLayerMediaType, map[string]any{
2730
"devcontainer-feature.json": "{}",
2831
})
2932
fs := memfs.New()
@@ -33,7 +36,7 @@ func TestExtract(t *testing.T) {
3336
t.Run("MissingFeatureFile", func(t *testing.T) {
3437
t.Parallel()
3538
registry := registrytest.New(t)
36-
ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{
39+
ref := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/test:latest", features.TarLayerMediaType, map[string]any{
3740
"install.sh": "hey",
3841
})
3942
fs := memfs.New()
@@ -43,7 +46,7 @@ func TestExtract(t *testing.T) {
4346
t.Run("MissingFeatureProperties", func(t *testing.T) {
4447
t.Parallel()
4548
registry := registrytest.New(t)
46-
ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{
49+
ref := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/test:latest", features.TarLayerMediaType, map[string]any{
4750
"install.sh": "hey",
4851
"devcontainer-feature.json": features.Spec{},
4952
})
@@ -54,7 +57,7 @@ func TestExtract(t *testing.T) {
5457
t.Run("Success", func(t *testing.T) {
5558
t.Parallel()
5659
registry := registrytest.New(t)
57-
ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{
60+
ref := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/test:latest", features.TarLayerMediaType, map[string]any{
5861
"install.sh": "hey",
5962
"devcontainer-feature.json": features.Spec{
6063
ID: "go",

go.mod

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ require (
3838
github.com/stretchr/testify v1.11.1
3939
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a
4040
go.uber.org/mock v0.4.0
41-
golang.org/x/crypto v0.40.0
42-
golang.org/x/mod v0.26.0
43-
golang.org/x/sync v0.16.0
41+
golang.org/x/crypto v0.45.0
42+
golang.org/x/mod v0.29.0
43+
golang.org/x/sync v0.18.0
4444
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
4545
)
4646

@@ -271,13 +271,13 @@ require (
271271
go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect
272272
go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516 // indirect
273273
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
274-
golang.org/x/net v0.42.0 // indirect
274+
golang.org/x/net v0.47.0 // indirect
275275
golang.org/x/oauth2 v0.30.0 // indirect
276-
golang.org/x/sys v0.34.0 // indirect
277-
golang.org/x/term v0.33.0 // indirect
278-
golang.org/x/text v0.27.0 // indirect
276+
golang.org/x/sys v0.38.0 // indirect
277+
golang.org/x/term v0.37.0 // indirect
278+
golang.org/x/text v0.31.0 // indirect
279279
golang.org/x/time v0.12.0 // indirect
280-
golang.org/x/tools v0.34.0 // indirect
280+
golang.org/x/tools v0.38.0 // indirect
281281
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
282282
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
283283
google.golang.org/appengine v1.6.8 // indirect

go.sum

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -838,8 +838,8 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0
838838
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
839839
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
840840
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
841-
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
842-
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
841+
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
842+
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
843843
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
844844
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
845845
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
@@ -851,8 +851,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
851851
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
852852
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
853853
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
854-
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
855-
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
854+
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
855+
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
856856
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
857857
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
858858
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -873,8 +873,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
873873
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
874874
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
875875
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
876-
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
877-
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
876+
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
877+
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
878878
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
879879
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
880880
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
@@ -887,8 +887,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
887887
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
888888
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
889889
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
890-
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
891-
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
890+
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
891+
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
892892
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
893893
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
894894
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -927,15 +927,15 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
927927
golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
928928
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
929929
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
930-
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
931-
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
930+
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
931+
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
932932
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
933933
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
934934
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
935935
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
936936
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
937-
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
938-
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
937+
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
938+
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
939939
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
940940
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
941941
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -945,8 +945,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
945945
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
946946
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
947947
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
948-
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
949-
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
948+
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
949+
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
950950
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
951951
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
952952
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
@@ -962,8 +962,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
962962
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
963963
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
964964
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
965-
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
966-
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
965+
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
966+
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
967967
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
968968
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
969969
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

integration/integration_test.go

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ QFBgc=
7272
-----END OPENSSH PRIVATE KEY-----`
7373
)
7474

75+
var emptyRemoteOpts []remote.Option
76+
7577
func TestLogs(t *testing.T) {
7678
t.Parallel()
7779

@@ -523,7 +525,7 @@ func TestBuildFromDevcontainerWithFeatures(t *testing.T) {
523525
t.Parallel()
524526

525527
registry := registrytest.New(t)
526-
feature1Ref := registrytest.WriteContainer(t, registry, "coder/test1:latest", features.TarLayerMediaType, map[string]any{
528+
feature1Ref := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/test1:latest", features.TarLayerMediaType, map[string]any{
527529
"devcontainer-feature.json": &features.Spec{
528530
ID: "test1",
529531
Name: "test1",
@@ -537,7 +539,7 @@ func TestBuildFromDevcontainerWithFeatures(t *testing.T) {
537539
"install.sh": "echo $BANANAS > /test1output",
538540
})
539541

540-
feature2Ref := registrytest.WriteContainer(t, registry, "coder/test2:latest", features.TarLayerMediaType, map[string]any{
542+
feature2Ref := registrytest.WriteContainer(t, registry, emptyRemoteOpts, "coder/test2:latest", features.TarLayerMediaType, map[string]any{
541543
"devcontainer-feature.json": &features.Spec{
542544
ID: "test2",
543545
Name: "test2",
@@ -603,6 +605,90 @@ func TestBuildFromDevcontainerWithFeatures(t *testing.T) {
603605
require.Equal(t, "hello from test 3!", strings.TrimSpace(test3Output))
604606
}
605607

608+
func TestBuildFromDevcontainerWithFeaturesInAuthRepo(t *testing.T) {
609+
t.Parallel()
610+
611+
// Given: an empty registry with auth enabled
612+
authOpts := setupInMemoryRegistryOpts{
613+
Username: "testing",
614+
Password: "testing",
615+
}
616+
remoteAuthOpt := append(emptyRemoteOpts, remote.WithAuth(&authn.Basic{Username: authOpts.Username, Password: authOpts.Password}))
617+
testReg := setupInMemoryRegistry(t, authOpts)
618+
regAuthJSON, err := json.Marshal(envbuilder.DockerConfig{
619+
AuthConfigs: map[string]clitypes.AuthConfig{
620+
testReg: {
621+
Username: authOpts.Username,
622+
Password: authOpts.Password,
623+
},
624+
},
625+
})
626+
require.NoError(t, err)
627+
628+
// push a feature to the registry
629+
featureRef := registrytest.WriteContainer(t, testReg, remoteAuthOpt, "features/test-feature:latest", features.TarLayerMediaType, map[string]any{
630+
"devcontainer-feature.json": &features.Spec{
631+
ID: "test1",
632+
Name: "test1",
633+
Version: "1.0.0",
634+
Options: map[string]features.Option{
635+
"bananas": {
636+
Type: "string",
637+
},
638+
},
639+
},
640+
"install.sh": "echo $BANANAS > /test1output",
641+
})
642+
643+
// Create a git repo with a devcontainer.json that uses the feature
644+
srv := gittest.CreateGitServer(t, gittest.Options{
645+
Files: map[string]string{
646+
".devcontainer/devcontainer.json": `{
647+
"name": "Test",
648+
"build": {
649+
"dockerfile": "Dockerfile"
650+
},
651+
"features": {
652+
"` + featureRef + `": {
653+
"bananas": "hello from test 1!"
654+
}
655+
}
656+
}`,
657+
".devcontainer/Dockerfile": "FROM " + testImageUbuntu,
658+
},
659+
})
660+
opts := []string{
661+
envbuilderEnv("GIT_URL", srv.URL),
662+
}
663+
664+
// Test that things fail when no auth is provided
665+
t.Run("NoAuth", func(t *testing.T) {
666+
t.Parallel()
667+
668+
// run the envbuilder with the auth config
669+
_, err := runEnvbuilder(t, runOpts{env: opts})
670+
require.ErrorContains(t, err, "Unauthorized")
671+
})
672+
673+
// test that things work when auth is provided
674+
t.Run("WithAuth", func(t *testing.T) {
675+
t.Parallel()
676+
677+
optsWithAuth := append(
678+
opts,
679+
envbuilderEnv("DOCKER_CONFIG_BASE64", base64.StdEncoding.EncodeToString(regAuthJSON)),
680+
)
681+
682+
// run the envbuilder with the auth config
683+
ctr, err := runEnvbuilder(t, runOpts{env: optsWithAuth})
684+
require.NoError(t, err)
685+
686+
// check that the feature was installed correctly
687+
testOutput := execContainer(t, ctr, "cat /test1output")
688+
require.Equal(t, "hello from test 1!", strings.TrimSpace(testOutput))
689+
})
690+
}
691+
606692
func TestBuildFromDockerfileAndConfig(t *testing.T) {
607693
t.Parallel()
608694

@@ -1574,7 +1660,7 @@ func TestPushImage(t *testing.T) {
15741660
t.Parallel()
15751661

15761662
// Write a test feature to an in-memory registry.
1577-
testFeature := registrytest.WriteContainer(t, registrytest.New(t), "features/test-feature:latest", features.TarLayerMediaType, map[string]any{
1663+
testFeature := registrytest.WriteContainer(t, registrytest.New(t), emptyRemoteOpts, "features/test-feature:latest", features.TarLayerMediaType, map[string]any{
15781664
"install.sh": `#!/bin/sh
15791665
echo "${MESSAGE}" > /root/message.txt`,
15801666
"devcontainer-feature.json": features.Spec{

testutil/registrytest/registrytest.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func New(t testing.TB, mws ...func(http.Handler) http.Handler) string {
4747

4848
// WriteContainer uploads a container to the registry server.
4949
// It returns the reference to the uploaded container.
50-
func WriteContainer(t *testing.T, serverURL, containerRef, mediaType string, files map[string]any) string {
50+
func WriteContainer(t *testing.T, serverURL string, remoteOpt []remote.Option, containerRef, mediaType string, files map[string]any) string {
5151
var buf bytes.Buffer
5252
hasher := crypto.SHA256.New()
5353
mw := io.MultiWriter(&buf, hasher)
@@ -110,7 +110,7 @@ func WriteContainer(t *testing.T, serverURL, containerRef, mediaType string, fil
110110
ref, err := name.ParseReference(strings.TrimPrefix(parsedStr, "http://"))
111111
require.NoError(t, err)
112112

113-
err = remote.Write(ref, image)
113+
err = remote.Write(ref, image, remoteOpt...)
114114
require.NoError(t, err)
115115

116116
return ref.String()

0 commit comments

Comments
 (0)