vctx: exec login and operator commands uncoloured; test signal forwarding
This commit is contained in:
+1
-1
@@ -71,7 +71,7 @@ coloured, SIGINT/SIGTERM are forwarded, and vault's exit code is returned
|
||||
Without colour (piped output, `NO_COLOR`, `table`/`raw`/`pretty` formats)
|
||||
`vctx` execs `vault` exactly as before, so scripts see unchanged output.
|
||||
Streaming or interactive commands (`monitor`, `debug`, `events`, `ssh`,
|
||||
`agent`, `proxy`, `server`) are always exec'd and never coloured. `JQ_COLORS`
|
||||
`agent`, `proxy`, `server`, `login`, `operator`) are always exec'd and never coloured. `JQ_COLORS`
|
||||
overrides the JSON palette as in `jq`.
|
||||
|
||||
## Flags
|
||||
|
||||
+5
-4
@@ -35,9 +35,10 @@ var execVault = syscall.Exec
|
||||
// osExit is swapped in tests to observe the child's exit code.
|
||||
var osExit = os.Exit
|
||||
|
||||
// streaming commands are never captured: buffering their stdout would hide
|
||||
// output until exit (or break the TTY, for ssh).
|
||||
var streaming = map[string]bool{"monitor": true, "debug": true, "events": true, "ssh": true, "agent": true, "proxy": true, "server": true}
|
||||
// uncaptured commands are always exec'd: buffering their stdout would hide
|
||||
// streamed output or prompts (unseal keys, MFA passcodes) until exit, or break
|
||||
// the TTY, for ssh.
|
||||
var uncaptured = map[string]bool{"monitor": true, "debug": true, "events": true, "ssh": true, "agent": true, "proxy": true, "server": true, "login": true, "operator": true}
|
||||
|
||||
func main() {
|
||||
if err := newRootCmd().Execute(); err != nil {
|
||||
@@ -269,7 +270,7 @@ func colourFormat(args, env []string) string {
|
||||
f = val
|
||||
}
|
||||
f = strings.ToLower(f)
|
||||
if streaming[cmd] || (f != "json" && f != "yaml") {
|
||||
if uncaptured[cmd] || (f != "json" && f != "yaml") {
|
||||
return ""
|
||||
}
|
||||
return f
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.unkin.net/unkin/vault-tools/shared"
|
||||
)
|
||||
@@ -278,6 +280,10 @@ func TestColourFormat(t *testing.T) {
|
||||
{[]string{"events", "subscribe", "kv*"}, []string{"VAULT_FORMAT=json"}, ""},
|
||||
{[]string{"monitor"}, []string{"VAULT_FORMAT=json"}, ""},
|
||||
{[]string{"ssh", "-format=json", "host"}, nil, ""},
|
||||
{[]string{"login", "-method=userpass"}, []string{"VAULT_FORMAT=json"}, ""},
|
||||
{[]string{"operator", "unseal"}, []string{"VAULT_FORMAT=json"}, ""},
|
||||
{[]string{"-format=yaml", "operator", "generate-root"}, nil, ""},
|
||||
{[]string{"operator", "rekey", "-format=json"}, nil, ""},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := colourFormat(c.args, c.env); got != c.want {
|
||||
@@ -323,6 +329,41 @@ func TestRunChild(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunChildForwardsSignal(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
bin := fakeVault(t, `trap 'echo TERM > "$D/got"; trap - TERM; kill -TERM $$' TERM
|
||||
touch "$D/ready"
|
||||
i=0; while [ $i -lt 100 ]; do sleep 0.05; i=$((i+1)); done`)
|
||||
type res struct {
|
||||
code int
|
||||
err error
|
||||
}
|
||||
ch := make(chan res, 1)
|
||||
go func() {
|
||||
code, err := runChild(bin, []string{bin}, append(os.Environ(), "D="+dir), "json", &bytes.Buffer{})
|
||||
ch <- res{code, err}
|
||||
}()
|
||||
for i := 0; i < 200; i++ {
|
||||
if _, err := os.Stat(filepath.Join(dir, "ready")); err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
if err := syscall.Kill(os.Getpid(), syscall.SIGTERM); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r := <-ch
|
||||
if r.err != nil {
|
||||
t.Fatal(r.err)
|
||||
}
|
||||
if got, _ := os.ReadFile(filepath.Join(dir, "got")); string(got) != "TERM\n" {
|
||||
t.Errorf("child did not receive SIGTERM (got %q)", got)
|
||||
}
|
||||
if r.code != 128+15 {
|
||||
t.Errorf("code = %d, want %d", r.code, 128+15)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunChildPassesArgsAndEnv(t *testing.T) {
|
||||
bin := fakeVault(t, `echo "{\"args\":\"$*\",\"tok\":\"$VAULT_TOKEN\"}"`)
|
||||
var out bytes.Buffer
|
||||
@@ -353,6 +394,8 @@ func TestRunVctxColourDecision(t *testing.T) {
|
||||
{"always", []string{"status"}, true},
|
||||
{"always", []string{"kv", "get", "kv/foo"}, false},
|
||||
{"always", []string{"read", "-format=json", "x"}, false},
|
||||
{"always", []string{"operator", "unseal", "-format=json"}, true},
|
||||
{"always", []string{"login", "-format=json"}, true},
|
||||
}
|
||||
for _, c := range cases {
|
||||
execed, exited := false, -1
|
||||
|
||||
Reference in New Issue
Block a user