@@ -146,7 +146,7 @@ func New(options Options) Agent {
146
146
logger : options .Logger ,
147
147
closeCancel : cancelFunc ,
148
148
closed : make (chan struct {}),
149
- envVars : options .EnvironmentVariables ,
149
+ environmentVariables : options .EnvironmentVariables ,
150
150
client : options .Client ,
151
151
exchangeToken : options .ExchangeToken ,
152
152
filesystem : options .Filesystem ,
@@ -169,6 +169,7 @@ func New(options Options) Agent {
169
169
prometheusRegistry : prometheusRegistry ,
170
170
metrics : newAgentMetrics (prometheusRegistry ),
171
171
}
172
+ a .serviceBanner .Store (& codersdk.ServiceBannerConfig {})
172
173
a .init (ctx )
173
174
return a
174
175
}
@@ -196,7 +197,7 @@ type agent struct {
196
197
closeMutex sync.Mutex
197
198
closed chan struct {}
198
199
199
- envVars map [string ]string
200
+ environmentVariables map [string ]string
200
201
201
202
manifest atomic.Pointer [agentsdk.Manifest ] // manifest is atomic because values can change after reconnection.
202
203
reportMetadataInterval time.Duration
@@ -235,14 +236,16 @@ func (a *agent) TailnetConn() *tailnet.Conn {
235
236
}
236
237
237
238
func (a * agent ) init (ctx context.Context ) {
238
- sshSrv , err := agentssh .NewServer (ctx , a .logger .Named ("ssh-server" ), a .prometheusRegistry , a .filesystem , a .sshMaxTimeout , "" )
239
+ sshSrv , err := agentssh .NewServer (ctx , a .logger .Named ("ssh-server" ), a .prometheusRegistry , a .filesystem , & agentssh.Config {
240
+ MaxTimeout : a .sshMaxTimeout ,
241
+ MOTDFile : func () string { return a .manifest .Load ().MOTDFile },
242
+ ServiceBanner : func () * codersdk.ServiceBannerConfig { return a .serviceBanner .Load () },
243
+ UpdateEnv : a .updateCommandEnv ,
244
+ WorkingDirectory : func () string { return a .manifest .Load ().Directory },
245
+ })
239
246
if err != nil {
240
247
panic (err )
241
248
}
242
- sshSrv .Env = a .envVars
243
- sshSrv .AgentToken = func () string { return * a .sessionToken .Load () }
244
- sshSrv .Manifest = & a .manifest
245
- sshSrv .ServiceBanner = & a .serviceBanner
246
249
a .sshServer = sshSrv
247
250
a .scriptRunner = agentscripts .New (agentscripts.Options {
248
251
LogDir : a .logDir ,
@@ -879,6 +882,80 @@ func (a *agent) run(ctx context.Context) error {
879
882
return eg .Wait ()
880
883
}
881
884
885
+ // updateCommandEnv updates the provided command environment with the
886
+ // following set of environment variables:
887
+ // -
888
+ func (a * agent ) updateCommandEnv (current []string ) (updated []string , err error ) {
889
+ manifest := a .manifest .Load ()
890
+ if manifest == nil {
891
+ return nil , xerrors .Errorf ("no manifest" )
892
+ }
893
+
894
+ executablePath , err := os .Executable ()
895
+ if err != nil {
896
+ return nil , xerrors .Errorf ("getting os executable: %w" , err )
897
+ }
898
+ unixExecutablePath := strings .ReplaceAll (executablePath , "\\ " , "/" )
899
+
900
+ // Define environment variables that should be set for all commands,
901
+ // and then merge them with the current environment.
902
+ envs := map [string ]string {
903
+ // Set env vars indicating we're inside a Coder workspace.
904
+ "CODER" : "true" ,
905
+ "CODER_WORKSPACE_NAME" : manifest .WorkspaceName ,
906
+ "CODER_WORKSPACE_AGENT_NAME" : manifest .AgentName ,
907
+
908
+ // Specific Coder subcommands require the agent token exposed!
909
+ "CODER_AGENT_TOKEN" : * a .sessionToken .Load (),
910
+
911
+ // Git on Windows resolves with UNIX-style paths.
912
+ // If using backslashes, it's unable to find the executable.
913
+ "GIT_SSH_COMMAND" : fmt .Sprintf ("%s gitssh --" , unixExecutablePath ),
914
+ // Hide Coder message on code-server's "Getting Started" page
915
+ "CS_DISABLE_GETTING_STARTED_OVERRIDE" : "true" ,
916
+ }
917
+
918
+ // This adds the ports dialog to code-server that enables
919
+ // proxying a port dynamically.
920
+ // If this is empty string, do not set anything. Code-server auto defaults
921
+ // using its basepath to construct a path based port proxy.
922
+ if manifest .VSCodePortProxyURI != "" {
923
+ envs ["VSCODE_PROXY_URI" ] = manifest .VSCodePortProxyURI
924
+ }
925
+
926
+ // Allow any of the current env to override what we defined above.
927
+ for _ , env := range current {
928
+ parts := strings .SplitN (env , "=" , 2 )
929
+ if len (parts ) != 2 {
930
+ continue
931
+ }
932
+ if _ , ok := envs [parts [0 ]]; ! ok {
933
+ envs [parts [0 ]] = parts [1 ]
934
+ }
935
+ }
936
+
937
+ // Load environment variables passed via the agent manifest.
938
+ // These override all variables we manually specify.
939
+ for k , v := range manifest .EnvironmentVariables {
940
+ // Expanding environment variables allows for customization
941
+ // of the $PATH, among other variables. Customers can prepend
942
+ // or append to the $PATH, so allowing expand is required!
943
+ envs [k ] = os .ExpandEnv (v )
944
+ }
945
+
946
+ // Agent-level environment variables should take over all. This is
947
+ // used for setting agent-specific variables like CODER_AGENT_TOKEN
948
+ // and GIT_ASKPASS.
949
+ for k , v := range a .environmentVariables {
950
+ envs [k ] = v
951
+ }
952
+
953
+ for k , v := range envs {
954
+ updated = append (updated , fmt .Sprintf ("%s=%s" , k , v ))
955
+ }
956
+ return updated , nil
957
+ }
958
+
882
959
func (a * agent ) wireguardAddresses (agentID uuid.UUID ) []netip.Prefix {
883
960
if len (a .addresses ) == 0 {
884
961
return []netip.Prefix {
@@ -1314,7 +1391,7 @@ func (a *agent) manageProcessPriorityLoop(ctx context.Context) {
1314
1391
}
1315
1392
}()
1316
1393
1317
- if val := a .envVars [EnvProcPrioMgmt ]; val == "" || runtime .GOOS != "linux" {
1394
+ if val := a .environmentVariables [EnvProcPrioMgmt ]; val == "" || runtime .GOOS != "linux" {
1318
1395
a .logger .Debug (ctx , "process priority not enabled, agent will not manage process niceness/oom_score_adj " ,
1319
1396
slog .F ("env_var" , EnvProcPrioMgmt ),
1320
1397
slog .F ("value" , val ),
0 commit comments