mirror of
https://github.com/go-task/task.git
synced 2026-02-24 12:10:47 +01:00
refactor: compute masked command at compile time
Move secret masking from runtime (task.go) to compile time (variables.go). This avoids recalculating variables on each log. - Add MaskSecretsWithExtra for loop vars and deferred commands - Rename CmdTemplate to LogCmd (clearer intent) - Simplify logging in runCommand
This commit is contained in:
@@ -35,3 +35,36 @@ func MaskSecrets(cmdTemplate string, vars *ast.Vars) string {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// MaskSecretsWithExtra is like MaskSecrets but also resolves extra variables (e.g., loop vars).
|
||||
func MaskSecretsWithExtra(cmdTemplate string, vars *ast.Vars, extra map[string]any) string {
|
||||
if vars == nil || vars.Len() == 0 {
|
||||
// Still need to resolve extra vars even if no vars
|
||||
cache := &Cache{Vars: ast.NewVars()}
|
||||
result := ReplaceWithExtra(cmdTemplate, cache, extra)
|
||||
if cache.Err() != nil {
|
||||
return cmdTemplate
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Create a cache map with secrets masked
|
||||
maskedVars := vars.DeepCopy()
|
||||
for name, v := range maskedVars.All() {
|
||||
if v.Secret {
|
||||
maskedVars.Set(name, ast.Var{
|
||||
Value: "*****",
|
||||
Secret: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cache := &Cache{Vars: maskedVars}
|
||||
result := ReplaceWithExtra(cmdTemplate, cache, extra)
|
||||
|
||||
if cache.Err() != nil {
|
||||
return cmdTemplate
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
14
task.go
14
task.go
@@ -349,8 +349,8 @@ func (e *Executor) runDeferred(t *ast.Task, call *Call, i int, vars *ast.Vars, d
|
||||
extra["EXIT_CODE"] = fmt.Sprintf("%d", *deferredExitCode)
|
||||
}
|
||||
|
||||
// Save template before resolving for secret masking in logs
|
||||
cmd.CmdTemplate = cmd.Cmd
|
||||
// Resolve template with secrets masked for logging
|
||||
cmd.LogCmd = templater.MaskSecretsWithExtra(cmd.Cmd, vars, extra)
|
||||
cmd.Cmd = templater.ReplaceWithExtra(cmd.Cmd, cache, extra)
|
||||
cmd.Task = templater.ReplaceWithExtra(cmd.Task, cache, extra)
|
||||
cmd.If = templater.ReplaceWithExtra(cmd.If, cache, extra)
|
||||
@@ -395,15 +395,7 @@ func (e *Executor) runCommand(ctx context.Context, t *ast.Task, call *Call, i in
|
||||
}
|
||||
|
||||
if e.Verbose || (!call.Silent && !cmd.Silent && !t.IsSilent() && !e.Taskfile.Silent && !e.Silent) {
|
||||
// Get runtime vars for masking
|
||||
varsForMasking, err := e.Compiler.FastGetVariables(t, call)
|
||||
if err != nil {
|
||||
return fmt.Errorf("task: failed to get variables: %w", err)
|
||||
}
|
||||
|
||||
// Mask secret variables in the command template before logging
|
||||
cmdToLog := templater.MaskSecrets(cmd.CmdTemplate, varsForMasking)
|
||||
e.Logger.Errf(logger.Green, "task: [%s] %s\n", t.Name(), cmdToLog)
|
||||
e.Logger.Errf(logger.Green, "task: [%s] %s\n", t.Name(), cmd.LogCmd)
|
||||
}
|
||||
|
||||
if e.Dry {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
// Cmd is a task command
|
||||
type Cmd struct {
|
||||
Cmd string // Resolved command (used for execution and fingerprinting)
|
||||
CmdTemplate string // Original template before variable resolution (used for secret masking)
|
||||
LogCmd string // Command with secrets masked (used for logging)
|
||||
Task string
|
||||
For *For
|
||||
If string
|
||||
@@ -29,7 +29,7 @@ func (c *Cmd) DeepCopy() *Cmd {
|
||||
}
|
||||
return &Cmd{
|
||||
Cmd: c.Cmd,
|
||||
CmdTemplate: c.CmdTemplate,
|
||||
LogCmd: c.LogCmd,
|
||||
Task: c.Task,
|
||||
For: c.For.DeepCopy(),
|
||||
If: c.If,
|
||||
|
||||
@@ -228,6 +228,8 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err
|
||||
extra["KEY"] = keys[i]
|
||||
}
|
||||
newCmd := cmd.DeepCopy()
|
||||
// Resolve template with secrets masked + loop vars for logging
|
||||
newCmd.LogCmd = templater.MaskSecretsWithExtra(cmd.Cmd, cache.Vars, extra)
|
||||
newCmd.Cmd = templater.ReplaceWithExtra(cmd.Cmd, cache, extra)
|
||||
newCmd.Task = templater.ReplaceWithExtra(cmd.Task, cache, extra)
|
||||
newCmd.If = templater.ReplaceWithExtra(cmd.If, cache, extra)
|
||||
@@ -243,7 +245,8 @@ func (e *Executor) compiledTask(call *Call, evaluateShVars bool) (*ast.Task, err
|
||||
continue
|
||||
}
|
||||
newCmd := cmd.DeepCopy()
|
||||
newCmd.CmdTemplate = cmd.Cmd
|
||||
// Resolve template with secrets masked for logging
|
||||
newCmd.LogCmd = templater.MaskSecrets(cmd.Cmd, cache.Vars)
|
||||
newCmd.Cmd = templater.Replace(cmd.Cmd, cache)
|
||||
newCmd.Task = templater.Replace(cmd.Task, cache)
|
||||
newCmd.If = templater.Replace(cmd.If, cache)
|
||||
|
||||
Reference in New Issue
Block a user