diff --git a/packages/cmd/agent.go b/packages/cmd/agent.go index 93ce80e5..e15ca59e 100644 --- a/packages/cmd/agent.go +++ b/packages/cmd/agent.go @@ -1932,7 +1932,7 @@ func (tm *AgentManager) MonitorSecretChanges(ctx context.Context, secretTemplate existingEtag = currentEtag - if !firstRun && execCommand != "" { + if execCommand != "" { log.Info().Msgf("executing command: %s", execCommand) err := ExecuteCommandWithTimeout(execCommand, execTimeout) diff --git a/packages/cmd/agent_execute_test.go b/packages/cmd/agent_execute_test.go new file mode 100644 index 00000000..f056464a --- /dev/null +++ b/packages/cmd/agent_execute_test.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "context" + "fmt" + "os" + "path/filepath" + "runtime" + "sync" + "testing" + "time" +) + +func TestMonitorSecretChanges_ExecutesCommandOnInitialRender(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("test command uses touch") + } + + tempDir := t.TempDir() + outputPath := filepath.Join(tempDir, "secrets.env") + markerPath := filepath.Join(tempDir, "command-ran") + + secretTemplate := Template{ + DestinationPath: outputPath, + TemplateContent: "SECRET=value", + } + secretTemplate.Config.PollingInterval = "1ms" + secretTemplate.Config.Execute.Command = fmt.Sprintf("touch %q", markerPath) + + manager := &AgentManager{ + accessToken: "test-token", + dynamicSecretLeases: &DynamicSecretLeaseManager{}, + templateFirstRenderOnce: map[int]*sync.Once{1: {}}, + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + done := make(chan struct{}) + go func() { + manager.MonitorSecretChanges(ctx, secretTemplate, 1, make(chan os.Signal), make(chan bool, 1)) + close(done) + }() + + deadline := time.After(time.Second) + for { + if _, err := os.Stat(markerPath); err == nil { + break + } else if !os.IsNotExist(err) { + t.Fatalf("check command marker: %v", err) + } + + select { + case <-deadline: + t.Fatal("execute command did not run after the initial render") + case <-time.After(time.Millisecond): + } + } + + cancel() + select { + case <-done: + case <-time.After(time.Second): + t.Fatal("secret monitor did not stop after context cancellation") + } +}