fix(summer): mask secret flag values in a delegate's error (WR-10)
This commit is contained in:
63
internal/argmask/argmask.go
Normal file
63
internal/argmask/argmask.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// Package argmask renders a command line for messages with the values of
|
||||
// secret-named long flags masked; bonfire's wrong-directory hint and
|
||||
// summer's delegate errors share it.
|
||||
package argmask
|
||||
|
||||
import "strings"
|
||||
|
||||
// secretWords mark a long flag whose value is masked.
|
||||
var secretWords = []string{"password", "passwd", "secret", "token", "key"}
|
||||
|
||||
// secretFlag reports whether the long flag name (without "--") looks like it
|
||||
// carries a secret.
|
||||
func secretFlag(name string) bool {
|
||||
name = strings.ToLower(name)
|
||||
for _, w := range secretWords {
|
||||
if strings.Contains(name, w) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Join renders args as one line, separated by single spaces and each
|
||||
// quoted for a shell (Quote). The value of a long flag named like a secret
|
||||
// becomes ***, in the "--flag=value" form and in the "--flag value" form,
|
||||
// so a password typed on the command line does not reach stderr and CI
|
||||
// logs. In the "--flag value" form the next argument is masked whatever its
|
||||
// first character (pflag takes "-Xk9" as the value too); only "--" is left
|
||||
// alone. Join cannot see flag types, so a secret-named boolean flag
|
||||
// over-masks the argument after it, which is the safe side.
|
||||
func Join(args []string) string {
|
||||
var b strings.Builder
|
||||
for i := 0; i < len(args); i++ {
|
||||
if i > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
a := args[i]
|
||||
name, long := strings.CutPrefix(a, "--")
|
||||
flag, _, inline := strings.Cut(name, "=")
|
||||
if !long || flag == "" || !secretFlag(flag) {
|
||||
b.WriteString(Quote(a))
|
||||
continue
|
||||
}
|
||||
if inline {
|
||||
b.WriteString(Quote("--"+flag) + "=***")
|
||||
continue
|
||||
}
|
||||
b.WriteString(Quote(a))
|
||||
if i+1 < len(args) && args[i+1] != "--" {
|
||||
b.WriteString(" ***")
|
||||
i++
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// Quote single-quotes s when a shell would split or expand it.
|
||||
func Quote(s string) string {
|
||||
if s != "" && !strings.ContainsAny(s, " \t\n'\"\\$`*?[]{}()<>|&;#~!") {
|
||||
return s
|
||||
}
|
||||
return "'" + strings.ReplaceAll(s, "'", `'\''`) + "'"
|
||||
}
|
||||
Reference in New Issue
Block a user