Skip to content

Commit 56f0389

Browse files
authored
implement cmd:jwt and fix remote execution of commands (#2292)
1 parent b81b824 commit 56f0389

7 files changed

Lines changed: 29 additions & 21 deletions

File tree

cmd/server/main-server.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,16 @@ func grabAndRemoveEnvVars() error {
271271
if err != nil {
272272
return err
273273
}
274+
275+
// Remove WAVETERM env vars that leak from prod => dev
276+
os.Unsetenv("WAVETERM_CLIENTID")
277+
os.Unsetenv("WAVETERM_WORKSPACEID")
278+
os.Unsetenv("WAVETERM_TABID")
279+
os.Unsetenv("WAVETERM_BLOCKID")
280+
os.Unsetenv("WAVETERM_CONN")
281+
os.Unsetenv("WAVETERM_JWT")
282+
os.Unsetenv("WAVETERM_VERSION")
283+
274284
return nil
275285
}
276286

docs/docs/customwidgets.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ The `WidgetConfigType` takes the usual options common to all widgets. The `MetaT
109109
| "cmd:env" | (optional) A key-value object represting environment variables to be run with the command. Defaults to an empty object. |
110110
| "cmd:cwd" | (optional) A string representing the current working directory to be run with the command. Currently only works locally. Defaults to the home directory. |
111111
| "cmd:nowsh" | (optional) A boolean that will turn off wsh integration for the command. Defaults to false. |
112+
| "cmd:jwt" | (optional) A boolean that forces adding JWT token to the environment. Required for running waveapps as widgets (both local and remote). Defaults to false. |
112113
| "term:localshellpath" | (optional) Sets the shell used for running your widget command. Only works locally. If left blank, wave will determine your system default instead. |
113114
| "term:localshellopts" | (optional) Sets the shell options meant to be used with `"term:localshellpath"`. This is useful if you are using a nonstandard shell and need to provide a specific option that we do not cover. Only works locally. Defaults to an empty string. |
114115
| "cmd:initscript" | (optional) for "shell" controller only. an init script to run before starting the shell (can be an inline script or an absolute local file path) |

frontend/types/gotypes.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ declare global {
536536
"cmd:args"?: string[];
537537
"cmd:shell"?: boolean;
538538
"cmd:allowconnchange"?: boolean;
539+
"cmd:jwt"?: boolean;
539540
"cmd:env"?: {[key: string]: string};
540541
"cmd:cwd"?: string;
541542
"cmd:initscript"?: string;

pkg/blockcontroller/blockcontroller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ func createCmdStrAndOpts(blockId string, blockMeta waveobj.MetaMapType, connName
369369
cmdStr = cmdStr + " " + utilfn.ShellQuote(arg, false, -1)
370370
}
371371
}
372+
cmdOpts.ForceJwt = blockMeta.GetBool(waveobj.MetaKey_CmdJwt, false)
372373
return cmdStr, &cmdOpts, nil
373374
}
374375

pkg/shellexec/shellexec.go

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"log"
1212
"os"
1313
"os/exec"
14-
"path/filepath"
1514
"runtime"
1615
"strings"
1716
"sync"
@@ -43,6 +42,7 @@ type CommandOptsType struct {
4342
ShellPath string `json:"shellPath,omitempty"`
4443
ShellOpts []string `json:"shellOpts,omitempty"`
4544
SwapToken *shellutil.TokenSwapEntry `json:"swapToken,omitempty"`
45+
ForceJwt bool `json:"forcejwt,omitempty"`
4646
}
4747

4848
type ShellProc struct {
@@ -212,6 +212,7 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st
212212
shellOpts = append(shellOpts, cmdOpts.ShellOpts...)
213213
shellType := shellutil.GetShellTypeFromShellPath(shellPath)
214214
conn.Infof(ctx, "detected shell type: %s\n", shellType)
215+
conn.Debugf(ctx, "cmdStr: %q\n", cmdStr)
215216

216217
if cmdStr == "" {
217218
/* transform command in order to inject environment vars */
@@ -245,7 +246,6 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st
245246
cmdCombined = fmt.Sprintf("%s %s", shellPath, strings.Join(shellOpts, " "))
246247
} else {
247248
// TODO check quoting of cmdStr
248-
shellPath = cmdStr
249249
shellOpts = append(shellOpts, "-c", cmdStr)
250250
cmdCombined = fmt.Sprintf("%s %s", shellPath, strings.Join(shellOpts, " "))
251251
}
@@ -266,6 +266,7 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st
266266
}
267267
jwtToken := cmdOpts.SwapToken.Env[wavebase.WaveJwtTokenVarName]
268268
if jwtToken != "" {
269+
conn.Debugf(ctx, "adding JWT token to environment\n")
269270
cmdCombined = fmt.Sprintf(`%s=%s %s`, wavebase.WaveJwtTokenVarName, jwtToken, cmdCombined)
270271
}
271272
log.Printf("full combined command: %s", cmdCombined)
@@ -363,6 +364,7 @@ func StartRemoteShellProc(ctx context.Context, logCtx context.Context, termSize
363364
shellType := shellutil.GetShellTypeFromShellPath(shellPath)
364365
conn.Infof(logCtx, "detected shell type: %s\n", shellType)
365366
conn.Infof(logCtx, "swaptoken: %s\n", cmdOpts.SwapToken.Token)
367+
conn.Debugf(logCtx, "cmdStr: %q\n", cmdStr)
366368

367369
if cmdStr == "" {
368370
/* transform command in order to inject environment vars */
@@ -396,7 +398,6 @@ func StartRemoteShellProc(ctx context.Context, logCtx context.Context, termSize
396398
cmdCombined = fmt.Sprintf("%s %s", shellPath, strings.Join(shellOpts, " "))
397399
} else {
398400
// TODO check quoting of cmdStr
399-
shellPath = cmdStr
400401
shellOpts = append(shellOpts, "-c", cmdStr)
401402
cmdCombined = fmt.Sprintf("%s %s", shellPath, strings.Join(shellOpts, " "))
402403
}
@@ -442,6 +443,11 @@ func StartRemoteShellProc(ctx context.Context, logCtx context.Context, termSize
442443
conn.Debugf(logCtx, "packed swaptoken %s\n", packedToken)
443444
cmdCombined = fmt.Sprintf(`%s=%s %s`, wavebase.WaveSwapTokenVarName, packedToken, cmdCombined)
444445
}
446+
jwtToken := cmdOpts.SwapToken.Env[wavebase.WaveJwtTokenVarName]
447+
if jwtToken != "" && cmdOpts.ForceJwt {
448+
conn.Debugf(logCtx, "adding JWT token to environment\n")
449+
cmdCombined = fmt.Sprintf(`%s=%s %s`, wavebase.WaveJwtTokenVarName, jwtToken, cmdCombined)
450+
}
445451
shellutil.AddTokenSwapEntry(cmdOpts.SwapToken)
446452
session.RequestPty("xterm-256color", termSize.Rows, termSize.Cols, nil)
447453
sessionWrap := MakeSessionWrap(session, cmdCombined, pipePty)
@@ -453,24 +459,6 @@ func StartRemoteShellProc(ctx context.Context, logCtx context.Context, termSize
453459
return &ShellProc{Cmd: sessionWrap, ConnName: conn.GetName(), CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil
454460
}
455461

456-
func isZshShell(shellPath string) bool {
457-
// get the base path, and then check contains
458-
shellBase := filepath.Base(shellPath)
459-
return strings.Contains(shellBase, "zsh")
460-
}
461-
462-
func isBashShell(shellPath string) bool {
463-
// get the base path, and then check contains
464-
shellBase := filepath.Base(shellPath)
465-
return strings.Contains(shellBase, "bash")
466-
}
467-
468-
func isFishShell(shellPath string) bool {
469-
// get the base path, and then check contains
470-
shellBase := filepath.Base(shellPath)
471-
return strings.Contains(shellBase, "fish")
472-
}
473-
474462
func StartLocalShellProc(logCtx context.Context, termSize waveobj.TermSize, cmdStr string, cmdOpts CommandOptsType) (*ShellProc, error) {
475463
shellutil.InitCustomShellStartupFiles()
476464
var ecmd *exec.Cmd
@@ -522,6 +510,11 @@ func StartLocalShellProc(logCtx context.Context, termSize waveobj.TermSize, cmdS
522510
blocklogger.Debugf(logCtx, "packed swaptoken %s\n", packedToken)
523511
shellutil.UpdateCmdEnv(ecmd, map[string]string{wavebase.WaveSwapTokenVarName: packedToken})
524512
}
513+
jwtToken := cmdOpts.SwapToken.Env[wavebase.WaveJwtTokenVarName]
514+
if jwtToken != "" && cmdOpts.ForceJwt {
515+
blocklogger.Debugf(logCtx, "adding JWT token to environment\n")
516+
shellutil.UpdateCmdEnv(ecmd, map[string]string{wavebase.WaveJwtTokenVarName: jwtToken})
517+
}
525518

526519
/*
527520
For Snap installations, we need to correct the XDG environment variables as Snap

pkg/waveobj/metaconsts.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const (
5151
MetaKey_CmdArgs = "cmd:args"
5252
MetaKey_CmdShell = "cmd:shell"
5353
MetaKey_CmdAllowConnChange = "cmd:allowconnchange"
54+
MetaKey_CmdJwt = "cmd:jwt"
5455
MetaKey_CmdEnv = "cmd:env"
5556
MetaKey_CmdCwd = "cmd:cwd"
5657
MetaKey_CmdInitScript = "cmd:initscript"

pkg/waveobj/wtypemeta.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type MetaTSType struct {
5050
CmdArgs []string `json:"cmd:args,omitempty"` // args for cmd (only if cmd:shell is false)
5151
CmdShell bool `json:"cmd:shell,omitempty"` // shell expansion for cmd+args (defaults to true)
5252
CmdAllowConnChange bool `json:"cmd:allowconnchange,omitempty"`
53+
CmdJwt bool `json:"cmd:jwt,omitempty"` // force adding JWT to environment
5354

5455
// these can be nested under "[conn]"
5556
CmdEnv map[string]string `json:"cmd:env,omitempty"`

0 commit comments

Comments
 (0)