diff --git a/test/common/testlib.py b/test/common/testlib.py index f4896e9b1793..01f763cd99a7 100644 --- a/test/common/testlib.py +++ b/test/common/testlib.py @@ -735,13 +735,6 @@ def wait_popup(self, elem_id: str) -> None: """ self.wait_visible('#' + elem_id) - def wait_popdown(self, elem_id: str) -> None: - """Wait for a popup to close. - - :param id: the 'id' attribute of the popup. - """ - self.wait_not_visible('#' + elem_id) - def wait_language(self, lang: str) -> None: parts = lang.split("-") code_1 = parts[0] @@ -1472,7 +1465,7 @@ def is_devel_build(self) -> bool: return os.environ.get('NODE_ENV') == 'development' def is_pybridge(self) -> bool: - # some tests start e.g. centos-7 as first machine, bridge may not exist there + # some tests start e.g. centos-8 as first machine, bridge may not exist there return any('python' in m.execute('head -c 30 /usr/bin/cockpit-bridge || true') for m in self.machines.values()) def disable_preload(self, *packages: str, machine: testvm.Machine | None = None) -> None: diff --git a/test/verify/check-shell-multi-os b/test/verify/check-shell-multi-os index 08828b9f0502..c5105389eacd 100755 --- a/test/verify/check-shell-multi-os +++ b/test/verify/check-shell-multi-os @@ -42,118 +42,6 @@ def add_machine(b, address, password): b.wait_not_present('#hosts_setup_server_dialog') -def wait_stock_addresses(b, expected): - b.wait_js_func( - """(function(expected) { - var nodes = document.querySelectorAll('#dashboard-hosts .list-group-item'); - var addresses = Array.prototype.map.call(nodes, function(e) { - return e.getAttribute("data-address"); - }); - return expected.sort().toString() == addresses.sort().toString(); - })""", expected) - - -def add_stock_machine(b, address, password): - b.click('#dashboard-add') - b.wait_popup('dashboard_setup_server_dialog') - b.set_input_text('#add-machine-address', address) - - b.click('#dashboard_setup_server_dialog button:contains(Add)') - b.wait_in_text('#dashboard_setup_server_dialog', "Fingerprint") - b.click('#dashboard_setup_server_dialog button:contains(Connect)') - if password: - b.wait_in_text('#dashboard_setup_server_dialog', "Unable to log in") - b.set_input_text('#login-custom-password', password) - b.click('#dashboard_setup_server_dialog button:contains(Log in)') - b.wait_popdown('dashboard_setup_server_dialog') - - -@testlib.skipDistroPackage() -class TestCentos7(testlib.MachineCase): - provision = { - "0": {"address": "10.111.113.1/20", "memory_mb": 512}, - "centos-7": {"address": "10.111.113.5/20", "image": "centos-7", "memory_mb": 512} - } - - def check_spawn(self, b, address): - # HACK: Firefox cannot do `cockpit.spawn` as it returns promise - # Firefox can wait for promise to resolve, but then cannot get value from it - if b.cdp.browser.name == "firefox": - return - result = b.call_js_func("""(function(address) { - return cockpit.spawn(['echo', 'hi'], { host: address }); - })""", address) - self.assertEqual(result, "hi\n") - - def check_dbus(self, b, address): - # HACK: Firefox cannot do `cockpit.dbus.proxy.call` as it returns promise - if b.cdp.browser.name == "firefox": - return - b.call_js_func("""(function(address) { - return cockpit.dbus("org.freedesktop.DBus", { host: address }) - .proxy("org.freedesktop.DBus", "/").call("GetId"); - })""", address) - - @testlib.todoPybridgeRHEL8() - def test(self): - dev_m = self.machine - dev_b = self.browser - - self.allow_hostkey_messages() - - self.login_and_go() - dev_b.click("#hosts-sel button") - dev_addresses = ["localhost"] - wait_addresses(dev_b, dev_addresses) - - stock_m = self.machines['centos-7'] - stock_m.execute("firewall-cmd --add-service cockpit") - stock_m.start_cockpit() - - # Wait for connectivity between the two - testlib.wait(lambda: stock_m.execute("ip addr >&2 && ping -q -w5 -c5 10.111.113.1")) - testlib.wait(lambda: dev_m.execute("ip addr >&2 && ping -q -w5 -c5 10.111.113.5")) - - stock_m.execute("hostnamectl set-hostname stock") - stock_b = self.new_browser(stock_m) - - stock_b.login_and_go("/dashboard", legacy_authorized=True) - wait_stock_addresses(stock_b, ["localhost"]) - - add_stock_machine(stock_b, "10.111.113.1", password=None) - wait_stock_addresses(stock_b, ["localhost", "10.111.113.1"]) - - add_machine(dev_b, "10.111.113.5", password="foobar") - dev_addresses.append("10.111.113.5") - wait_addresses(dev_b, dev_addresses) - - stock_b.switch_to_top() - self.check_dbus(stock_b, "10.111.113.1") - self.check_dbus(dev_b, "10.111.113.5") - - self.check_spawn(stock_b, "10.111.113.1") - self.check_spawn(dev_b, "10.111.113.5") - - dev_b.go("/@10.111.113.5/network") - dev_b.wait_visible("iframe.container-frame[name='cockpit1:10.111.113.5/network'][src$='/network/index.html#/']") - - dev_b.go("/@10.111.113.5/storage") - dev_b.wait_visible("iframe.container-frame[name='cockpit1:10.111.113.5/storage'][src$='/storage/index.html#/']") - - dev_b.switch_to_top() - dev_b.go("/@10.111.113.5/users") - dev_b.wait_visible("iframe.container-frame[name='cockpit1:10.111.113.5/users'][src$='/users/index.html#/']") - - stock_b.go("/@10.111.113.1/system") - stock_b.wait_visible("iframe.container-frame[name='cockpit1:10.111.113.1/system'][data-loaded]") - stock_b.switch_to_frame('cockpit1:10.111.113.1/system') - stock_b.wait_text_not("#system_information_hardware_text", "") - - # Messages from previous versions of cockpit - self.allow_journal_messages(".*pam_authenticate failed: Authentication failure") - self.allow_restart_journal_messages() - - @testlib.skipDistroPackage() class TestRHEL8(testlib.MachineCase): provision = { @@ -197,11 +85,11 @@ class TestRHEL8(testlib.MachineCase): class TestMultiOSDirect(testlib.MachineCase): provision = { "0": {"address": "10.111.113.1/20", "memory_mb": 512}, - "centos-7": {"address": "10.111.113.5/20", "image": "centos-7", "memory_mb": 512} + "stock": {"address": "10.111.113.5/20", "image": "centos-8-stream", "memory_mb": 512} } @testlib.todoPybridgeRHEL8() - def testCentos7Direct(self): + def testCentos8Direct(self): b = self.browser self.allow_hostkey_messages() @@ -212,7 +100,7 @@ class TestMultiOSDirect(testlib.MachineCase): dev_addresses = ["localhost"] wait_addresses(b, dev_addresses) - stock_m = self.machines['centos-7'] + stock_m = self.machines['stock'] stock_m.execute("hostnamectl set-hostname stock") add_machine(b, "10.111.113.5", password="foobar") @@ -222,12 +110,7 @@ class TestMultiOSDirect(testlib.MachineCase): # Access stock directly from dev b.open("/=10.111.113.5") - b.wait_visible("#login") - b.wait_not_visible("#badge") - b.wait_not_visible("#brand") - b.set_input_text("#login-user-input", "admin") - b.set_input_text("#login-password-input", "foobar") - b.click('#login-button') + b.try_login(superuser=False) b.wait_visible("#hostkey-group") b.wait_in_text("#hostkey-message-1", "You are connecting to 10.111.113.5 for the first time.") b.click('#login-button') @@ -237,7 +120,7 @@ class TestMultiOSDirect(testlib.MachineCase): b.wait_visible("iframe.container-frame[name='cockpit1:localhost/system']") b.switch_to_frame("cockpit1:localhost/system") b.wait_visible("body") - b.wait_in_text('#system_information_hostname_button', "stock") + b.wait_in_text('#system_information_hostname_text', "stock") b.switch_to_top() b.wait_js_cond('window.location.pathname == "/=10.111.113.5/system"') diff --git a/test/verify/check-superuser b/test/verify/check-superuser index a796453f15e6..60f3fbaedb5e 100755 --- a/test/verify/check-superuser +++ b/test/verify/check-superuser @@ -22,14 +22,6 @@ import time import testlib -def allow_old_cockpit_ws_messages(test): - # noisy debug message from old cockpit-ws/polkit - test.allow_journal_messages("logged in user session", - "New connection to session from.*", - "pam_unix(polkit-1:session): session opened for user root by .*uid=.*", - "admin: Executing command .*COMMAND=.*cockpit-bridge --privileged.*") - - @testlib.nondestructive @testlib.skipDistroPackage() class TestSuperuser(testlib.MachineCase): @@ -407,151 +399,6 @@ session include system-auth b.wait_not_present(".pf-v5-c-alert:contains('Web console is running in limited access mode.')") -@testlib.skipDistroPackage() -class TestSuperuserOldShell(testlib.MachineCase): - provision = { - "machine1": {"address": "10.111.113.1/20", "memory_mb": 512}, - "machine2": {"address": "10.111.113.2/20", "image": "centos-7", "memory_mb": 512}, - } - - def test(self): - b = self.browser - m = self.machine - - m.start_cockpit() - - # Use m1 to login into m2 - b.open("/") - b.wait_visible("#login") - b.set_val("#login-user-input", "admin") - b.set_val("#login-password-input", "foobar") - b.click("#show-other-login-options") - b.wait_visible("#server-group") - b.set_val("#server-field", "10.111.113.2") - b.click('#login-button') - b.wait_in_text("#server-name", "10.111.113.2") - b.wait_visible("#hostkey-group") - b.wait_in_text("#hostkey-message-1", "You are connecting to 10.111.113.2 for the first time.") - b.click('#login-button') - b.wait_visible('#content') - - # The old shell should have gotten the password from cockpit-ws and it should work - b.enter_page("/system") - b.click("#shutdown-group > button:contains('Restart')") - b.wait_popup("shutdown-dialog") - b.click("#shutdown-dialog button:contains('Restart')") - b.wait_popdown("shutdown-dialog") - - -@testlib.skipImage("TODO: broken on Arch Linux", "arch") -@testlib.skipDistroPackage() -class TestSuperuserOldWebserver(testlib.MachineCase): - provision = { - "machine1": {"address": "10.111.113.1/20", "image": "centos-7", "memory_mb": 512}, - "machine2": {"address": "10.111.113.2/20", "memory_mb": 512}, - } - - def test(self): - b = self.browser - m = self.machine - - allow_old_cockpit_ws_messages(self) - - m.execute("firewall-cmd --add-service cockpit") - m.start_cockpit() - - # Use m1 to login into m2 - b.open("/") - b.wait_visible("#login") - b.set_val("#login-user-input", "admin") - b.set_val("#login-password-input", "foobar") - b.set_checked('#authorized-input', val=True) - b.click("#show-other-login-options") - b.wait_visible("#server-group") - b.set_val("#server-field", "10.111.113.2") - b.click('#login-button') - b.wait_in_text("#server-name", "10.111.113.2") - b.wait_in_text("#conversation-prompt", "Fingerprint") - b.wait_in_text("#conversation-message", "Do you want to proceed this time?") - b.click('#login-button') - b.wait_visible('#content') - - if not self.is_pybridge(): - # The C bridge will recognize that it is being started by - # a old webserver (or old bridge) and will start "any" - # privileged bridge during startup. - b.check_superuser_indicator("Administrative access") - b.go("/playground/test") - b.enter_page("/playground/test") - b.click(".super-channel button") - b.wait_in_text(".super-channel span", 'result: ') - self.assertIn('result: uid=0', b.text(".super-channel span")) - - else: - # The Python bridge will not start any privileged bridge - # if not explicitly told, and a old webserver (or old - # bridge) does not tell it anything. - b.check_superuser_indicator("Limited access") - b.go("/playground/test") - b.enter_page("/playground/test") - b.click(".super-channel button") - b.wait_in_text(".super-channel span", 'access-denied') - - b.become_superuser() - b.go("/playground/test") - b.enter_page("/playground/test") - b.click(".super-channel button") - b.wait_in_text(".super-channel span", 'result: ') - self.assertIn('result: uid=0', b.text(".super-channel span")) - - def testNotAuth(self): - b = self.browser - m = self.machine - - allow_old_cockpit_ws_messages(self) - - m.execute("firewall-cmd --add-service cockpit") - m.start_cockpit() - - # Use m1 to login into m2, but don't reuse the password - b.open("/") - b.wait_visible("#login") - b.set_val("#login-user-input", "admin") - b.set_val("#login-password-input", "foobar") - b.set_checked('#authorized-input', val=False) - b.click("#show-other-login-options") - b.wait_visible("#server-group") - b.set_val("#server-field", "10.111.113.2") - b.click('#login-button') - b.wait_in_text("#server-name", "10.111.113.2") - b.wait_in_text("#conversation-prompt", "Fingerprint") - b.wait_in_text("#conversation-message", "Do you want to proceed this time?") - b.click('#login-button') - b.wait_visible('#content') - - # We should not have gotten the password from the old - # cockpit-ws, but we can get it back. - - b.check_superuser_indicator("Limited access") - b.go("/playground/test") - b.enter_page("/playground/test") - b.click(".super-channel button") - b.wait_in_text(".super-channel span", 'access-denied') - - b.switch_to_top() - b.open_superuser_dialog() - b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:") - b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar") - b.click(".pf-v5-c-modal-box button:contains('Authenticate')") - b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')") - b.check_superuser_indicator("Administrative access") - b.go("/playground/test") - b.enter_page("/playground/test") - b.click(".super-channel button") - b.wait_in_text(".super-channel span", 'result: ') - self.assertIn('result: uid=0', b.text(".super-channel span")) - - @testlib.skipDistroPackage() class TestSuperuserDashboard(testlib.MachineCase): provision = { @@ -629,124 +476,5 @@ class TestSuperuserDashboard(testlib.MachineCase): self.allow_hostkey_messages() -@testlib.skipDistroPackage() -class TestSuperuserOldDashboard(testlib.MachineCase): - provision = { - "machine1": {"address": "10.111.113.1/20", "image": "centos-7", "memory_mb": 512}, - "machine2": {"address": "10.111.113.2/20", "memory_mb": 512}, - } - - def test(self): - b = self.browser - m = self.machines["machine1"] - - allow_old_cockpit_ws_messages(self) - self.allow_hostkey_messages() - self.setup_provisioned_hosts() - - m.execute("firewall-cmd --add-service cockpit") - m.start_cockpit() - - # Log into m1 and add m2 - b.open("/") - b.wait_visible("#login") - b.set_val("#login-user-input", "admin") - b.set_val("#login-password-input", "foobar") - b.set_checked('#authorized-input', val=True) - b.click('#login-button') - b.wait_visible('#content') - - b.go("/@10.111.113.2") - b.click('#machine-troubleshoot') - b.wait_popup('troubleshoot-dialog') - b.click('#troubleshoot-dialog button:contains("Add")') - b.wait_in_text('#troubleshoot-dialog', "Fingerprint") - b.click('#troubleshoot-dialog button:contains("Connect")') - b.wait_popdown('troubleshoot-dialog') - - # There should be a superuser button in the Overview of machine2 - - def get_admin(): - b.go("/@10.111.113.2") - b.enter_page("/system", host="10.111.113.2") - b.click(".ct-overview-header-actions button:contains('Limited access')") - b.wait_in_text(".pf-v5-c-modal-box:contains('Switch to administrative access')", "Password for admin:") - b.set_input_text(".pf-v5-c-modal-box:contains('Switch to administrative access') input", "foobar") - b.click(".pf-v5-c-modal-box button:contains('Authenticate')") - b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to administrative access')") - b.wait_visible(".ct-overview-header-actions button:contains('Administrative access')") - b.go("/@10.111.113.2/playground/test") - b.enter_page("/playground/test", host="10.111.113.2") - b.click(".super-channel button") - b.wait_in_text(".super-channel span", 'result: ') - self.assertIn('result: uid=0', b.text(".super-channel span")) - - def drop_admin(): - b.go("/@10.111.113.2") - b.enter_page("/system", host="10.111.113.2") - b.click(".ct-overview-header-actions button:contains('Administrative access')") - b.click(".pf-v5-c-modal-box:contains('Switch to limited access') button:contains('Limit access')") - b.wait_not_present(".pf-v5-c-modal-box:contains('Switch to limited access')") - b.wait_visible(".ct-overview-header-actions button:contains('Limited access')") - b.go("/@10.111.113.2/playground/test") - b.enter_page("/playground/test", host="10.111.113.2") - b.click(".super-channel button") - b.wait_in_text(".super-channel span", 'access-denied') - - if not self.is_pybridge(): - # The C bridge will recognize that it is being started by - # a old bridge (or old webserver) and will start "any" - # privileged bridge during startup. So we have admin at - # this point. - # - drop_admin() - get_admin() - - else: - # The Python bridge will not start any privileged bridge - # if not explicitly told, and a old bridge (or old - # webserver) does not tell it anything. So we don't have - # admin at this point. - # - get_admin() - drop_admin() - - -@testlib.skipDistroPackage() -class TestSuperuserDashboardOldMachine(testlib.MachineCase): - provision = { - "machine1": {"address": "10.111.113.1/20"}, - "machine2": {"address": "10.111.113.2/20", "image": "centos-7"}, - } - - @testlib.todoPybridgeRHEL8() - def test(self): - b = self.browser - - self.setup_provisioned_hosts() - self.login_and_go() - b.go("/@10.111.113.2") - b.click('#machine-troubleshoot') - b.wait_visible('#hosts_setup_server_dialog') - b.click('#hosts_setup_server_dialog button:contains("Add")') - b.wait_in_text('#hosts_setup_server_dialog', "You are connecting to 10.111.113.2 for the first time.") - b.click('#hosts_setup_server_dialog button.pf-m-primary') - b.wait_in_text('#hosts_setup_server_dialog', "Unable to log in") - b.set_input_text("#login-custom-password", "foobar") - b.click('#hosts_setup_server_dialog button:contains("Log in")') - b.wait_not_present('#hosts_setup_server_dialog') - - # Since user and password are the same on machine2, we should - # have gotten admin rights. - - b.enter_page("/system", host="10.111.113.2") - b.click("#shutdown-group > button:contains('Restart')") - b.wait_popup("shutdown-dialog") - b.click("#shutdown-dialog button:contains('Restart')") - b.wait_popdown("shutdown-dialog") - - self.allow_hostkey_messages() - - if __name__ == '__main__': testlib.test_main()