@@ -59,6 +59,376 @@ var protectionTests = []struct {
5959 },
6060}
6161
62+ << << << < HEAD
63+ == == == =
64+ func TestUpgradeAgentWithTamperProtectedEndpoint_DEB (t * testing.T ) {
65+ info := define .Require (t , define.Requirements {
66+ Group : integration .Deb ,
67+ Stack : & define.Stack {},
68+ Local : false , // requires Agent installation
69+ Sudo : true , // requires Agent installation
70+ OS : []define.OS {
71+ {
72+ Type : define .Linux ,
73+ },
74+ },
75+ })
76+
77+ t .Run ("Upgrade from older version to newer version" , func (t * testing.T ) {
78+ upgradeFromVersion , err := upgradetest .PreviousMinor ()
79+ require .NoError (t , err )
80+ testTamperProtectedInstallUpgrade (t , info , "deb" , upgradeFromVersion .String (), true , false )
81+ })
82+
83+ t .Run ("Install same version over the installed agent" , func (t * testing.T ) {
84+ t .Skip ("This constantly fails, so skipping until further investigation is done and a fix is implemented" )
85+ testTamperProtectedInstallUpgrade (t , info , "deb" , define .Version (), false , false )
86+ })
87+
88+ t .Run ("Upgrade with endpoint stopped before upgrade" , func (t * testing.T ) {
89+ upgradeFromVersion , err := upgradetest .PreviousMinor ()
90+ require .NoError (t , err )
91+ testTamperProtectedInstallUpgrade (t , info , "deb" , upgradeFromVersion .String (), true , true )
92+ })
93+
94+ t .Run ("Make sure unprotected upgrades are not broken" , func (t * testing.T ) {
95+ testUnprotectedInstallUpgrade (t , info , "deb" )
96+ })
97+ }
98+
99+ func TestUpgradeAgentWithTamperProtectedEndpoint_RPM (t * testing.T ) {
100+ info := define .Require (t , define.Requirements {
101+ Group : integration .RPM ,
102+ Stack : & define.Stack {},
103+ Local : false , // requires Agent installation
104+ Sudo : true , // requires Agent installation
105+ OS : []define.OS {
106+ {
107+ Type : define .Linux ,
108+ Distro : "rhel" ,
109+ },
110+ },
111+ })
112+
113+ t .Run ("Upgrade from older version to newer version" , func (t * testing.T ) {
114+ upgradeFromVersion , err := upgradetest .PreviousMinor ()
115+ require .NoError (t , err )
116+ testTamperProtectedInstallUpgrade (t , info , "rpm" , upgradeFromVersion .String (), true , false )
117+ })
118+
119+ t .Run ("Install same version over the installed agent" , func (t * testing.T ) {
120+ testTamperProtectedInstallUpgrade (t , info , "rpm" , define .Version (), false , false )
121+ })
122+
123+ t .Run ("Upgrade with endpoint stopped before upgrade" , func (t * testing.T ) {
124+ upgradeFromVersion , err := upgradetest .PreviousMinor ()
125+ require .NoError (t , err )
126+ testTamperProtectedInstallUpgrade (t , info , "rpm" , upgradeFromVersion .String (), true , true )
127+ })
128+ t .Run ("Make sure unprotected upgrades are not broken" , func (t * testing.T ) {
129+ testUnprotectedInstallUpgrade (t , info , "rpm" )
130+ })
131+ }
132+
133+ func getEndpointVersion (t * testing.T ) string {
134+ cmd := exec .Command ("sudo" , "/opt/Elastic/Endpoint/elastic-endpoint" , "version" )
135+ output , err := cmd .CombinedOutput ()
136+ require .NoError (t , err )
137+ // version: 8.18.0-SNAPSHOT, compiled: Wed Feb 19 01:00:00 2025, branch: HEAD, commit: c450b50f91507c3166b072df8557f5efd871103a
138+ endpointVersionFragment , _ , found := strings .Cut (string (output ), "," )
139+ require .True (t , found )
140+
141+ endpointVersion , found := strings .CutPrefix (endpointVersionFragment , "version: " )
142+ require .True (t , found )
143+
144+ return endpointVersion
145+ }
146+
147+ func getInstallCommand (ctx context.Context , packageFormat string , srcPkg string , envVars []string ) (* exec.Cmd , error ) {
148+ args := []string {}
149+
150+ if len (envVars ) != 0 {
151+ args = append (args , envVars ... )
152+ }
153+
154+ switch packageFormat {
155+ case "deb" :
156+ // since the previous agent is enrolled it means that the /etc/elastic-agent/elastic-agent.yml has changed
157+ // and dpkg will ask if we want to overwrite it. Since this is a non-interactive install we need to
158+ // force to keep the existing config
159+ args = append (args , "dpkg" , "--force-confold" , "-i" )
160+ case "rpm" :
161+ args = append (args , "rpm" , "-Uvh" , "--force" )
162+ default :
163+ return nil , fmt .Errorf ("unknown package format for install command: %s" , packageFormat )
164+ }
165+ args = append (args , srcPkg )
166+ return exec .CommandContext (ctx , "sudo" , args ... ), nil
167+ }
168+
169+ func addEndpointCleanup (t * testing.T , uninstallToken string ) {
170+ t .Cleanup (func () {
171+ _ , err := os .Stat ("/opt/Elastic/Endpoint/elastic-endpoint" )
172+ if os .IsNotExist (err ) {
173+ t .Log ("Endpoint binary does not exist, aborting endpoint cleanup" )
174+ return
175+ }
176+
177+ out , err := exec .Command ("sudo" , "systemctl" , "stop" , "ElasticEndpoint" ).CombinedOutput ()
178+ if err != nil {
179+ t .Log (string (out ))
180+ t .Logf ("error while stopping Elastic Endpoint: %s" , err .Error ())
181+ }
182+
183+ if atesting .KeepInstalledFlag () {
184+ t .Logf ("\" Keep installed\" flag is set, won't be removing endpoint. If you want to remove endpoint later on, use the following uninstall token: %s" , uninstallToken )
185+ return
186+ }
187+
188+ uninstallContext , uninstallCancel := context .WithTimeout (context .Background (), 5 * time .Minute )
189+ defer uninstallCancel ()
190+
191+ t .Logf ("Uninstalling endpoint with the following uinstall token: %s" , uninstallToken )
192+ _ , err = exec .CommandContext (uninstallContext , "/opt/Elastic/Endpoint/elastic-endpoint" , "uninstall" , "--uninstall-token" , uninstallToken ).CombinedOutput ()
193+ if err != nil {
194+ t .Fatalf ("error when cleaning up elastic-endpoint: uninstall token %s" , uninstallToken )
195+ }
196+
197+ t .Log ("Endpoint is successfully uninstalled by the cleanup function" )
198+ })
199+ }
200+
201+ func installFirstAgent (ctx context.Context , t * testing.T , info * define.Info , isProtected bool , packageFormat string , upgradeFromVersion string ) (* atesting.Fixture , string ) {
202+ var fixture * atesting.Fixture
203+ var err error
204+
205+ if upgradeFromVersion == define .Version () {
206+ fixture , err = define .NewFixtureFromLocalBuild (t , define .Version (), atesting .WithPackageFormat (packageFormat ))
207+ } else {
208+ fixture , err = atesting .NewFixture (
209+ t ,
210+ upgradeFromVersion ,
211+ atesting .WithFetcher (atesting .ArtifactFetcher ()),
212+ atesting .WithPackageFormat (packageFormat ),
213+ )
214+ }
215+ require .NoError (t , err , "failed to create fixture" )
216+ err = fixture .Prepare (ctx )
217+ require .NoError (t , err , "failed to prepare fixture" )
218+
219+ t .Log ("Creating a generic policy and enrollment token" )
220+ policy := createBasicPolicy ()
221+ policyResp , enrollKeyResp := createPolicyAndEnrollmentToken (ctx , t , info .KibanaClient , policy )
222+
223+ t .Log ("Install elastic defend" )
224+ pkgPolicyResp , err := installElasticDefendPackage (t , info , policyResp .ID )
225+ require .NoErrorf (t , err , "Policy Response was: %v" , pkgPolicyResp )
226+
227+ updateReq := kibana.AgentPolicyUpdateRequest {
228+ Name : policy .Name ,
229+ Namespace : policy .Namespace ,
230+ IsProtected : & isProtected ,
231+ }
232+
233+ t .Log ("Updating the policy to set \" is_protected\" to true" )
234+ _ , err = info .KibanaClient .UpdatePolicy (ctx , policyResp .ID , updateReq )
235+
236+ t .Log ("Get the policy uninstall token" )
237+ uninstallToken , err := tools .GetUninstallToken (ctx , info .KibanaClient , policyResp .ID )
238+ require .NoError (t , err , "failed to get uninstall token" )
239+
240+ opts := atesting.InstallOpts {}
241+ t .Log ("Install and enroll the first agent" )
242+ _ , err = tools .InstallAgentForPolicyWithToken (ctx , t , opts , fixture , info .KibanaClient , enrollKeyResp )
243+ require .NoError (t , err , "failed to install agent for policy with token" )
244+
245+ addEndpointCleanup (t , uninstallToken )
246+
247+ agentClient := fixture .Client ()
248+ err = agentClient .Connect (ctx )
249+ require .NoError (t , err , "could not connect to the initial agent" )
250+
251+ require .Eventually (t ,
252+ func () bool { return agentAndEndpointAreHealthy (t , ctx , agentClient ) },
253+ endpointHealthPollingTimeout ,
254+ time .Second ,
255+ "Endpoint component or units are not healthy prior to upgrade." ,
256+ )
257+
258+ t .Log ("The initial installation of both the agent and endpoint are healthy" )
259+
260+ return fixture , uninstallToken
261+ }
262+
263+ func testUnprotectedInstallUpgrade (
264+ t * testing.T ,
265+ info * define.Info ,
266+ packageFormat string ,
267+ ) {
268+ ctx := t .Context ()
269+
270+ upgradeFromVersion , err := upgradetest .PreviousMinor ()
271+ require .NoError (t , err )
272+
273+ installFirstAgent (ctx , t , info , false , packageFormat , upgradeFromVersion .String ())
274+
275+ initEndpointVersion := getEndpointVersion (t )
276+ t .Logf ("The initial endpoint version is %s" , initEndpointVersion )
277+
278+ t .Log ("Setup agent fixture with the test build" )
279+ fixture , err := define .NewFixtureFromLocalBuild (t , define .Version (), atesting .WithPackageFormat (packageFormat ))
280+ require .NoError (t , err )
281+ err = fixture .Prepare (ctx )
282+ require .NoError (t , err , "failed to prepare fixture" )
283+
284+ t .Log ("Getting source package" )
285+ srcPkg , err := fixture .SrcPackage (ctx )
286+ require .NoError (t , err )
287+
288+ t .Log ("Installing the second agent, upgrading from the older version" )
289+ installCmd , err := getInstallCommand (ctx , fixture .PackageFormat (), srcPkg , nil )
290+ require .NoError (t , err )
291+
292+ out , err := installCmd .CombinedOutput ()
293+ t .Log (string (out ))
294+ require .NoError (t , err , "agent installation with package manager should not fail" )
295+
296+ err = fixture .SetDebRpmClient ()
297+ require .NoError (t , err , "could not set DEB/RPM client" )
298+
299+ upgradedAgentClient := fixture .Client ()
300+ err = upgradedAgentClient .Connect (ctx )
301+ require .NoError (t , err , "could not connect to the upgraded agent" )
302+
303+ require .Eventually (t ,
304+ func () bool { return agentAndEndpointAreHealthy (t , ctx , upgradedAgentClient ) },
305+ endpointHealthPollingTimeout ,
306+ time .Second ,
307+ "Endpoint component or units are not healthy after the upgrade." ,
308+ )
309+
310+ t .Log ("Validate that the initial endpoint version is smaller than the upgraded version" )
311+ upgradedEndpointVersion := getEndpointVersion (t )
312+ t .Logf ("The upgraded endpoint version is %s" , upgradedEndpointVersion )
313+
314+ startEndpointVersion , err := version .ParseVersion (initEndpointVersion )
315+ require .NoError (t , err )
316+
317+ parsedUpgradedVersion , err := version .ParseVersion (upgradedEndpointVersion )
318+ require .NoError (t , err )
319+
320+ t .Logf ("Comparing start version %s to upgraded version %s" , startEndpointVersion .String (), parsedUpgradedVersion .String ())
321+ require .True (t , startEndpointVersion .Less (* parsedUpgradedVersion ))
322+
323+ t .Log ("trying to uinstall without token, not expecting error" )
324+ out , err = exec .Command ("sudo" , "elastic-agent" , "uninstall" , "-f" ).CombinedOutput ()
325+ t .Log (string (out ))
326+ require .NoError (t , err )
327+
328+ _ , err = exec .LookPath ("elastic-agent" )
329+ require .Error (t , err )
330+
331+ t .Log ("successfully uninstalled agent and endpoint" )
332+ }
333+
334+ func testTamperProtectedInstallUpgrade (
335+ t * testing.T ,
336+ info * define.Info ,
337+ packageFormat string ,
338+ initialVersion string ,
339+ checkVersionUpgrade bool ,
340+ stopEndpointBeforeUpgrade bool ,
341+ ) {
342+ ctx := t .Context ()
343+
344+ fixture , uninstallToken := installFirstAgent (ctx , t , info , true , packageFormat , initialVersion )
345+
346+ initEndpointVersion := getEndpointVersion (t )
347+ t .Logf ("The initial endpoint version is %s" , initEndpointVersion )
348+
349+ // Optionally stop the endpoint service before upgrade
350+ if stopEndpointBeforeUpgrade {
351+ t .Log ("Stopping endpoint service before upgrade as requested" )
352+ out , err := exec .Command ("sudo" , "systemctl" , "stop" , "ElasticEndpoint" ).CombinedOutput ()
353+ t .Log (string (out ))
354+ require .NoError (t , err , "failed to stop ElasticEndpoint before upgrade" )
355+ }
356+
357+ // try to uninstall the agent without a token and assert failure
358+ out , err := exec .Command ("sudo" , "elastic-agent" , "uninstall" , "-f" ).CombinedOutput ()
359+ t .Log (string (out ))
360+ require .Error (t , err , "uninstalling agent without a token should fail because of tamper protection" )
361+ t .Log ("Tamper protection for the initial installation of the agent is enabled" )
362+
363+ if checkVersionUpgrade {
364+ t .Log ("Setup agent fixture with the test build" )
365+ fixture , err = define .NewFixtureFromLocalBuild (t , define .Version (), atesting .WithPackageFormat (packageFormat ))
366+ require .NoError (t , err , "failed to create agent fixture" )
367+ err = fixture .Prepare (ctx )
368+ require .NoError (t , err , "failed to prepare agent fixture" )
369+ }
370+
371+ t .Log ("Getting source package" )
372+ srcPkg , err := fixture .SrcPackage (ctx )
373+ require .NoError (t , err , "failed to get source package" )
374+
375+ t .Log ("Installing the second agent, upgrading from the older version" )
376+ installCmd , err := getInstallCommand (ctx , fixture .PackageFormat (), srcPkg , nil )
377+ require .NoError (t , err , "failed to get install command" )
378+
379+ out , err = installCmd .CombinedOutput ()
380+ t .Log (string (out ))
381+ require .NoError (t , err , "agent installation with package manager should not fail" )
382+
383+ err = fixture .SetDebRpmClient ()
384+ require .NoError (t , err , "failed to set deb/rpm client" )
385+
386+ upgradedAgentClient := fixture .Client ()
387+ err = upgradedAgentClient .Connect (ctx )
388+ require .NoError (t , err , "could not connect to the upgraded agent" )
389+
390+ require .Eventually (t ,
391+ func () bool { return agentAndEndpointAreHealthy (t , ctx , upgradedAgentClient ) },
392+ endpointHealthPollingTimeout ,
393+ time .Second ,
394+ "Endpoint component or units are not healthy after the upgrade." ,
395+ )
396+
397+ if checkVersionUpgrade {
398+ t .Log ("Validate that the initial endpoint version is smaller than the upgraded version" )
399+ upgradedEndpointVersion := getEndpointVersion (t )
400+ t .Logf ("The upgraded endpoint version is %s" , upgradedEndpointVersion )
401+
402+ startEndpointVersion , err := version .ParseVersion (initEndpointVersion )
403+ require .NoError (t , err , "failed to parse initial endpoint version" )
404+
405+ parsedUpgradedVersion , err := version .ParseVersion (upgradedEndpointVersion )
406+ require .NoError (t , err , "failed to parse upgraded endpoint version" )
407+
408+ t .Logf ("Comparing start version %s to upgraded version %s" , startEndpointVersion .String (), parsedUpgradedVersion .String ())
409+ require .True (t , startEndpointVersion .Less (* parsedUpgradedVersion ))
410+ }
411+
412+ // try to uninstall the agent without token and assert that endpoint is not removed
413+ t .Log ("trying to uninstall without token, expecting error" )
414+ out , err = exec .Command ("sudo" , "elastic-agent" , "uninstall" , "-f" ).CombinedOutput ()
415+ t .Log (string (out ))
416+ require .Error (t , err , "uninstalling agent without a token should fail because of tamper protection" )
417+ t .Log ("tamper protection for the upgraded agent is enabled" )
418+
419+ // uninstall with the token and assert that endpoint is indeed removed.
420+ t .Log ("trying to uninstall with token, not expecting any error" )
421+ out , err = exec .Command ("sudo" , "elastic-agent" , "uninstall" , "-f" , "--uninstall-token" , uninstallToken ).CombinedOutput ()
422+ t .Log (string (out ))
423+ require .NoError (t , err , string (out ))
424+
425+ _ , err = exec .LookPath ("elastic-agent" )
426+ require .Error (t , err , "expected elastic-agent binary to not exist in PATH after uninstall" )
427+
428+ t .Log ("successfully uninstalled endpoint using the uninstall token" )
429+ }
430+
431+ >> >> >> > e9cc69aec (skip : TestUpgradeAgentWithTamperProtectedEndpoint_DEB install same version over the installed agent (#9244 ))
62432// TestInstallAndCLIUninstallWithEndpointSecurity tests that the agent can
63433// install and uninstall the endpoint-security service while remaining healthy.
64434//
0 commit comments