@@ -8,13 +8,75 @@ import (
8
8
"os/exec"
9
9
"os/user"
10
10
"path/filepath"
11
+ "strconv"
11
12
"strings"
12
13
"testing"
13
14
"time"
14
15
15
16
"github.com/stretchr/testify/require"
16
17
)
17
18
19
+ // getUserInfo returns information about the current user, handling sudo scenarios
20
+ func getUserInfo () (string , int , int , string , string ) {
21
+ // Only consider SUDO_USER if we're actually running with elevated privileges
22
+ // In environments like Coder workspaces, SUDO_USER may be set to 'root'
23
+ // but we're not actually running under sudo
24
+ if sudoUser := os .Getenv ("SUDO_USER" ); sudoUser != "" && os .Geteuid () == 0 && sudoUser != "root" {
25
+ // We're actually running under sudo with a non-root original user
26
+ user , err := user .Lookup (sudoUser )
27
+ if err != nil {
28
+ return getCurrentUserInfo () // Fallback to current user
29
+ }
30
+
31
+ uid , _ := strconv .Atoi (os .Getenv ("SUDO_UID" ))
32
+ gid , _ := strconv .Atoi (os .Getenv ("SUDO_GID" ))
33
+
34
+ // If we couldn't get UID/GID from env, parse from user info
35
+ if uid == 0 {
36
+ if parsedUID , err := strconv .Atoi (user .Uid ); err == nil {
37
+ uid = parsedUID
38
+ }
39
+ }
40
+ if gid == 0 {
41
+ if parsedGID , err := strconv .Atoi (user .Gid ); err == nil {
42
+ gid = parsedGID
43
+ }
44
+ }
45
+
46
+ configDir := getConfigDir (user .HomeDir )
47
+
48
+ return sudoUser , uid , gid , user .HomeDir , configDir
49
+ }
50
+
51
+ // Not actually running under sudo, use current user
52
+ return getCurrentUserInfo ()
53
+ }
54
+
55
+ // getCurrentUserInfo gets information for the current user
56
+ func getCurrentUserInfo () (string , int , int , string , string ) {
57
+ currentUser , err := user .Current ()
58
+ if err != nil {
59
+ // Fallback with empty values if we can't get user info
60
+ return "" , 0 , 0 , "" , ""
61
+ }
62
+
63
+ uid , _ := strconv .Atoi (currentUser .Uid )
64
+ gid , _ := strconv .Atoi (currentUser .Gid )
65
+
66
+ configDir := getConfigDir (currentUser .HomeDir )
67
+
68
+ return currentUser .Username , uid , gid , currentUser .HomeDir , configDir
69
+ }
70
+
71
+ // getConfigDir determines the config directory based on XDG_CONFIG_HOME or fallback
72
+ func getConfigDir (homeDir string ) string {
73
+ // Use XDG_CONFIG_HOME if set, otherwise fallback to ~/.config/coder_boundary
74
+ if xdgConfigHome := os .Getenv ("XDG_CONFIG_HOME" ); xdgConfigHome != "" {
75
+ return filepath .Join (xdgConfigHome , "coder_boundary" )
76
+ }
77
+ return filepath .Join (homeDir , ".config" , "coder_boundary" )
78
+ }
79
+
18
80
// findProjectRoot finds the project root by looking for go.mod file
19
81
func findProjectRoot (t * testing.T ) string {
20
82
cwd , err := os .Getwd ()
@@ -131,10 +193,18 @@ func TestBoundaryIntegration(t *testing.T) {
131
193
fmt .Printf ("u.Username: %v\n " , u .Username )
132
194
fmt .Printf ("u.HomeDir: %v\n " , u .HomeDir )
133
195
196
+ sudoUser , uid , gid , homeDir , configDir := getUserInfo ()
197
+ fmt .Printf ("sudoUser: %v\n " , sudoUser )
198
+ fmt .Printf ("uid: %v\n " , uid )
199
+ fmt .Printf ("gid: %v\n " , gid )
200
+ fmt .Printf ("homeDir: %v\n " , homeDir )
201
+ fmt .Printf ("configDir: %v\n " , configDir )
202
+ certPath := fmt .Sprintf ("%v/ca-cert.pem" , configDir )
203
+
134
204
// Run curl directly in the namespace using ip netns exec
135
205
// TODO(yevhenii): remove env
136
206
curlCmd := exec .Command ("sudo" , "ip" , "netns" , "exec" , namespaceName ,
137
- "env" , "SSL_CERT_FILE=/home/coder/.config/coder_boundary/ca-cert.pem" , "curl" , "-s" , "https://dev.coder.com/api/v2" )
207
+ "env" , fmt . Sprintf ( "SSL_CERT_FILE=%v" , certPath ) , "curl" , "-s" , "https://dev.coder.com/api/v2" )
138
208
139
209
// Capture stderr separately
140
210
var stderr bytes.Buffer
0 commit comments