Skip to content

Commit 816d8a3

Browse files
committed
Merge branch 'main' of github.com:coder/envbuilder into bq/docs
2 parents c8cbdf5 + dbe4135 commit 816d8a3

File tree

7 files changed

+282
-154
lines changed

7 files changed

+282
-154
lines changed

devcontainer/devcontainer_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
"github.com/coder/envbuilder/devcontainer"
1414
"github.com/coder/envbuilder/devcontainer/features"
15-
"github.com/coder/envbuilder/registrytest"
15+
"github.com/coder/envbuilder/testutil/registrytest"
1616
"github.com/go-git/go-billy/v5/memfs"
1717
"github.com/google/go-containerregistry/pkg/name"
1818
v1 "github.com/google/go-containerregistry/pkg/v1"

devcontainer/features/features_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"testing"
66

77
"github.com/coder/envbuilder/devcontainer/features"
8-
"github.com/coder/envbuilder/registrytest"
8+
"github.com/coder/envbuilder/testutil/registrytest"
99
"github.com/go-git/go-billy/v5/memfs"
1010
"github.com/stretchr/testify/require"
1111
)

envbuilder.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,8 @@ func Run(ctx context.Context, c *Config, fs billy.Filesystem, logger Logger) err
198198
}
199199

200200
if c.GitUsername != "" || c.GitPassword != "" {
201-
gitURL, err := url.Parse(c.GitURL)
202-
if err != nil {
203-
return fmt.Errorf("parse git url: %w", err)
204-
}
205-
gitURL.User = url.UserPassword(c.GitUsername, c.GitPassword)
206-
c.GitURL = gitURL.String()
207-
201+
// NOTE: we previously inserted the credentials into the repo URL.
202+
// This was removed in https://github.com/coder/envbuilder/pull/141
208203
cloneOpts.RepoAuth = &githttp.BasicAuth{
209204
Username: c.GitUsername,
210205
Password: c.GitPassword,

git_test.go

Lines changed: 144 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,168 @@ package envbuilder_test
22

33
import (
44
"context"
5+
"fmt"
56
"io"
67
"net/http/httptest"
8+
"net/url"
79
"os"
10+
"regexp"
811
"testing"
9-
"time"
1012

1113
"github.com/coder/envbuilder"
12-
"github.com/coder/envbuilder/gittest"
14+
"github.com/coder/envbuilder/testutil/gittest"
15+
"github.com/go-git/go-billy/v5"
1316
"github.com/go-git/go-billy/v5/memfs"
14-
"github.com/go-git/go-git/v5"
15-
"github.com/go-git/go-git/v5/plumbing/object"
17+
githttp "github.com/go-git/go-git/v5/plumbing/transport/http"
1618
"github.com/stretchr/testify/require"
1719
)
1820

1921
func TestCloneRepo(t *testing.T) {
2022
t.Parallel()
2123

22-
t.Run("Clones", func(t *testing.T) {
23-
t.Parallel()
24+
for _, tc := range []struct {
25+
name string
26+
srvUsername string
27+
srvPassword string
28+
username string
29+
password string
30+
mungeURL func(*string)
31+
expectError string
32+
expectClone bool
33+
}{
34+
{
35+
name: "no auth",
36+
expectClone: true,
37+
},
38+
{
39+
name: "auth",
40+
srvUsername: "user",
41+
srvPassword: "password",
42+
username: "user",
43+
password: "password",
44+
expectClone: true,
45+
},
46+
{
47+
name: "auth but no creds",
48+
srvUsername: "user",
49+
srvPassword: "password",
50+
expectClone: false,
51+
expectError: "authentication required",
52+
},
53+
{
54+
name: "invalid auth",
55+
srvUsername: "user",
56+
srvPassword: "password",
57+
username: "notuser",
58+
password: "notpassword",
59+
expectClone: false,
60+
expectError: "authentication required",
61+
},
62+
{
63+
name: "tokenish username",
64+
srvUsername: "tokentokentoken",
65+
srvPassword: "",
66+
username: "tokentokentoken",
67+
password: "",
68+
expectClone: true,
69+
},
70+
} {
71+
tc := tc
72+
t.Run(tc.name, func(t *testing.T) {
73+
t.Parallel()
2474

25-
serverFS := memfs.New()
26-
repo := gittest.NewRepo(t, serverFS)
27-
tree, err := repo.Worktree()
28-
require.NoError(t, err)
75+
// We do not overwrite a repo if one is already present.
76+
t.Run("AlreadyCloned", func(t *testing.T) {
77+
srvFS := memfs.New()
78+
_ = gittest.NewRepo(t, srvFS, gittest.Commit(t, "README.md", "Hello, world!", "Wow!"))
79+
authMW := gittest.BasicAuthMW(tc.srvUsername, tc.srvPassword)
80+
srv := httptest.NewServer(authMW(gittest.NewServer(srvFS)))
81+
clientFS := memfs.New()
82+
// A repo already exists!
83+
_ = gittest.NewRepo(t, clientFS)
84+
cloned, err := envbuilder.CloneRepo(context.Background(), envbuilder.CloneRepoOptions{
85+
Path: "/",
86+
RepoURL: srv.URL,
87+
Storage: clientFS,
88+
})
89+
require.NoError(t, err)
90+
require.False(t, cloned)
91+
})
2992

30-
gittest.WriteFile(t, serverFS, "README.md", "Hello, world!")
31-
_, err = tree.Add("README.md")
32-
require.NoError(t, err)
33-
commit, err := tree.Commit("Wow!", &git.CommitOptions{
34-
Author: &object.Signature{
35-
Name: "Example",
36-
37-
When: time.Now(),
38-
},
39-
})
40-
require.NoError(t, err)
41-
_, err = repo.CommitObject(commit)
42-
require.NoError(t, err)
93+
// Basic Auth
94+
t.Run("BasicAuth", func(t *testing.T) {
95+
t.Parallel()
96+
srvFS := memfs.New()
97+
_ = gittest.NewRepo(t, srvFS, gittest.Commit(t, "README.md", "Hello, world!", "Wow!"))
98+
authMW := gittest.BasicAuthMW(tc.srvUsername, tc.srvPassword)
99+
srv := httptest.NewServer(authMW(gittest.NewServer(srvFS)))
100+
clientFS := memfs.New()
43101

44-
srv := httptest.NewServer(gittest.NewServer(serverFS))
102+
cloned, err := envbuilder.CloneRepo(context.Background(), envbuilder.CloneRepoOptions{
103+
Path: "/workspace",
104+
RepoURL: srv.URL,
105+
Storage: clientFS,
106+
RepoAuth: &githttp.BasicAuth{
107+
Username: tc.username,
108+
Password: tc.password,
109+
},
110+
})
111+
require.Equal(t, tc.expectClone, cloned)
112+
if tc.expectError != "" {
113+
require.ErrorContains(t, err, tc.expectError)
114+
return
115+
}
116+
require.NoError(t, err)
117+
require.True(t, cloned)
45118

46-
clientFS := memfs.New()
47-
cloned, err := envbuilder.CloneRepo(context.Background(), envbuilder.CloneRepoOptions{
48-
Path: "/workspace",
49-
RepoURL: srv.URL,
50-
Storage: clientFS,
51-
})
52-
require.NoError(t, err)
53-
require.True(t, cloned)
119+
readme := mustRead(t, clientFS, "/workspace/README.md")
120+
require.Equal(t, "Hello, world!", readme)
121+
gitConfig := mustRead(t, clientFS, "/workspace/.git/config")
122+
// Ensure we do not modify the git URL that folks pass in.
123+
require.Regexp(t, fmt.Sprintf(`(?m)^\s+url\s+=\s+%s\s*$`, regexp.QuoteMeta(srv.URL)), gitConfig)
124+
})
125+
126+
// In-URL-style auth e.g. http://user:password@host:port
127+
t.Run("InURL", func(t *testing.T) {
128+
t.Parallel()
129+
srvFS := memfs.New()
130+
_ = gittest.NewRepo(t, srvFS, gittest.Commit(t, "README.md", "Hello, world!", "Wow!"))
131+
authMW := gittest.BasicAuthMW(tc.srvUsername, tc.srvPassword)
132+
srv := httptest.NewServer(authMW(gittest.NewServer(srvFS)))
54133

55-
file, err := clientFS.OpenFile("/workspace/README.md", os.O_RDONLY, 0644)
56-
require.NoError(t, err)
57-
defer file.Close()
58-
content, err := io.ReadAll(file)
59-
require.NoError(t, err)
60-
require.Equal(t, "Hello, world!", string(content))
61-
})
134+
authURL, err := url.Parse(srv.URL)
135+
require.NoError(t, err)
136+
authURL.User = url.UserPassword(tc.username, tc.password)
137+
clientFS := memfs.New()
62138

63-
t.Run("DoesntCloneIfRepoExists", func(t *testing.T) {
64-
t.Parallel()
65-
clientFS := memfs.New()
66-
gittest.NewRepo(t, clientFS)
67-
cloned, err := envbuilder.CloneRepo(context.Background(), envbuilder.CloneRepoOptions{
68-
Path: "/",
69-
RepoURL: "https://example.com",
70-
Storage: clientFS,
139+
cloned, err := envbuilder.CloneRepo(context.Background(), envbuilder.CloneRepoOptions{
140+
Path: "/workspace",
141+
RepoURL: authURL.String(),
142+
Storage: clientFS,
143+
})
144+
require.Equal(t, tc.expectClone, cloned)
145+
if tc.expectError != "" {
146+
require.ErrorContains(t, err, tc.expectError)
147+
return
148+
}
149+
require.NoError(t, err)
150+
require.True(t, cloned)
151+
152+
readme := mustRead(t, clientFS, "/workspace/README.md")
153+
require.Equal(t, "Hello, world!", readme)
154+
gitConfig := mustRead(t, clientFS, "/workspace/.git/config")
155+
// Ensure we do not modify the git URL that folks pass in.
156+
require.Regexp(t, fmt.Sprintf(`(?m)^\s+url\s+=\s+%s\s*$`, regexp.QuoteMeta(authURL.String())), gitConfig)
157+
})
71158
})
72-
require.NoError(t, err)
73-
require.False(t, cloned)
74-
})
159+
}
160+
}
161+
162+
func mustRead(t *testing.T, fs billy.Filesystem, path string) string {
163+
t.Helper()
164+
f, err := fs.OpenFile(path, os.O_RDONLY, 0644)
165+
require.NoError(t, err)
166+
content, err := io.ReadAll(f)
167+
require.NoError(t, err)
168+
return string(content)
75169
}

0 commit comments

Comments
 (0)