@@ -137,6 +137,114 @@ func (s *procmgrWindowsSuite) SetupSuite() {
137137 s .tryInstallWindowsDDOTForProcmgr ()
138138}
139139
140+ func (s * procmgrWindowsSuite ) TestProcmgrServiceRunsAsLocalSystem () {
141+ s .requireCLI ()
142+ host := s .Env ().RemoteHost
143+
144+ require .EventuallyWithT (s .T (), func (ct * assert.CollectT ) {
145+ owner , err := windowsProcessOwnerByName (host , "dd-procmgrd.exe" )
146+ assert .NoError (ct , err )
147+ assert .Contains (ct , owner , "NT AUTHORITY/SYSTEM" )
148+ }, 60 * time .Second , 2 * time .Second )
149+ }
150+
151+ func (s * procmgrWindowsSuite ) TestAgentProfileChildRunsAsAgentUser () {
152+ s .requireCLI ()
153+ host := s .Env ().RemoteHost
154+
155+ require .EventuallyWithT (s .T (), func (ct * assert.CollectT ) {
156+ desc := host .MustExecuteOn (ct , s .platform .cliCmd ("describe test-sleep" ))
157+ assertField (ct , desc , "State" , "Running" )
158+ pid := fieldValue (desc , "PID" )
159+ if ! assert .NotEmpty (ct , pid ) {
160+ return
161+ }
162+ owner , err := windowsProcessOwnerByPID (host , pid )
163+ assert .NoError (ct , err )
164+ assert .NotContains (ct , owner , "NT AUTHORITY/SYSTEM" )
165+ }, 60 * time .Second , 2 * time .Second )
166+ }
167+
168+ func (s * procmgrWindowsSuite ) TestAgentProfileDescribeUserMatchesRuntimeUser () {
169+ s .requireCLI ()
170+ host := s .Env ().RemoteHost
171+
172+ _ , agentUser , err := windowsagent .GetAgentUserFromRegistry (host )
173+ require .NoError (s .T (), err )
174+
175+ require .EventuallyWithT (s .T (), func (ct * assert.CollectT ) {
176+ desc := host .MustExecuteOn (ct , s .platform .cliCmd ("describe test-sleep" ))
177+ assertField (ct , desc , "State" , "Running" )
178+ assertField (ct , desc , "Profile" , "agent" )
179+ assertHasField (ct , desc , "User" )
180+ assertHasField (ct , desc , "Runtime User" )
181+
182+ user := fieldValue (desc , "User" )
183+ runtimeUser := fieldValue (desc , "Runtime User" )
184+ assert .NotEmpty (ct , user )
185+ assert .NotEmpty (ct , runtimeUser )
186+ assert .Equal (ct , user , runtimeUser ,
187+ "describe User should match Runtime User for agent-profile children" )
188+ // MSI stores the machine name as installedDomain for local ddagentuser;
189+ // procmgr display normalizes local SAM accounts to .\user.
190+ assert .Equal (ct , `.\` + agentUser , user ,
191+ "local agent user should use registry-style .\\ user display" )
192+ }, 60 * time .Second , 2 * time .Second )
193+ }
194+
195+ func (s * procmgrWindowsSuite ) TestAgentProfileChildHasUserProfileEnv () {
196+ s .requireCLI ()
197+ host := s .Env ().RemoteHost
198+
199+ _ , agentUser , err := windowsagent .GetAgentUserFromRegistry (host )
200+ require .NoError (s .T (), err )
201+
202+ markerPath := `C:\ProgramData\Datadog\procmgr-e2e-userprofile.txt`
203+ // Use forward slashes inside the YAML double-quoted arg: backslashes are escape sequences in YAML.
204+ markerPathForYAML := `C:/ProgramData/Datadog/procmgr-e2e-userprofile.txt`
205+ yamlPath := joinWindowsPath (winConfigDir , "test-userprofile-env.yaml" )
206+ yamlContent := fmt .Sprintf (`command: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
207+ args:
208+ - "-NoProfile"
209+ - "-NonInteractive"
210+ - "-Command"
211+ - "$env:USERPROFILE | Set-Content -LiteralPath '%s'"
212+ env:
213+ SystemRoot: C:\Windows
214+ PATH: C:\Windows\System32;C:\Windows
215+ auto_start: true
216+ restart: always
217+ description: E2E userprofile env check
218+ ` , markerPathForYAML )
219+
220+ host .MustExecute (writeProcessesDYamlContent (yamlPath , yamlContent ))
221+ // Register marker cleanup first so it runs after yaml removal and reload (LIFO).
222+ defer func () {
223+ _ , _ = host .Execute (psRemote (`Remove-Item -LiteralPath '%s' -Force -ErrorAction SilentlyContinue` , markerPath ))
224+ }()
225+ defer func () {
226+ _ , _ = host .Execute (psRemote (`Remove-Item -LiteralPath '%s' -Force -ErrorAction SilentlyContinue` , yamlPath ))
227+ _ , _ = host .Execute (s .platform .cliCmd ("reload" ))
228+ }()
229+
230+ reloadOut , err := host .Execute (s .platform .cliCmd ("reload" ))
231+ require .NoError (s .T (), err )
232+ assert .Contains (s .T (), reloadOut , "test-userprofile-env" , "reload output: %s" , reloadOut )
233+
234+ require .EventuallyWithT (s .T (), func (ct * assert.CollectT ) {
235+ desc := host .MustExecuteOn (ct , s .platform .cliCmd ("describe test-userprofile-env" ))
236+ assertField (ct , desc , "State" , "Running" )
237+ }, 60 * time .Second , 2 * time .Second )
238+
239+ require .EventuallyWithT (s .T (), func (ct * assert.CollectT ) {
240+ out := host .MustExecuteOn (ct , psRemote (`Get-Content -LiteralPath '%s' -ErrorAction Stop` , markerPath ))
241+ userProfile := strings .TrimSpace (out )
242+ assert .NotEmpty (ct , userProfile )
243+ assert .NotContains (ct , strings .ToLower (userProfile ), "systemprofile" )
244+ assert .Contains (ct , strings .ToLower (userProfile ), strings .ToLower (agentUser ))
245+ }, 120 * time .Second , 2 * time .Second )
246+ }
247+
140248// tryInstallWindowsDDOTForProcmgr bootstraps DDOT under procmgr when embedded otel-agent is on the image.
141249func (s * procmgrWindowsSuite ) tryInstallWindowsDDOTForProcmgr () {
142250 s .T ().Helper ()
0 commit comments