From 5670965e9d7f59f2d98c3c129a2625bc1906228d Mon Sep 17 00:00:00 2001 From: max Date: Thu, 24 Sep 2026 17:37:45 +0200 Subject: [PATCH] test(licensing): add tests for .lic package import, upstream CA persistence, and seat expansion --- tests/test_license_authority.py | 80 ++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/tests/test_license_authority.py b/tests/test_license_authority.py index 746ae3e..cb76537 100644 --- a/tests/test_license_authority.py +++ b/tests/test_license_authority.py @@ -202,6 +202,82 @@ class TestLicenseAuthorityAndWebUI(unittest.TestCase): self.assertEqual(summary2["active_seats"], 2) self.assertEqual(summary2["available_seats"], 0) + def test_activated_lic_package_import_and_renewal_seat_increase(self): + """Verifies that an activated .lic package can be imported, saving upstream_ca, and renewal expands seats.""" + # 1. Generate CSR on server side + csr_pem, _ = enrollment.generate_ca_csr(cert_dir=self.server_cert_dir) + + # 2. Authority signs it with 20 seats and produces activated .lic + issued = authority.issue_license_from_csr( + csr_pem=csr_pem, + seats=20, + server_fingerprint="FP_TEST_HUB", + hostname="hub.enterprise.local", + db_path=self.db_path, + cert_dir=self.master_ca_dir + ) + self.assertIn("lic_package", issued) + self.assertIn("lic_json", issued) + + # Write .lic file + lic_file = os.path.join(self.test_dir, "test_activated.lic") + with open(lic_file, "w", encoding="utf-8") as f: + f.write(issued["lic_json"]) + + # 3. Server imports .lic package + import_res = enrollment.import_license_package(lic_file, cert_dir=self.server_cert_dir) + self.assertEqual(import_res["seats"], 20) + self.assertEqual(import_res["license_id"], issued["license_id"]) + self.assertTrue(os.path.exists(os.path.join(self.server_cert_dir, "ca.crt"))) + self.assertTrue(os.path.exists(os.path.join(self.server_cert_dir, "upstream_ca.crt"))) + + # 4. Initialize server state and verify summary + Server.init_db(self.server_db, max_seats=20) + Server.SERVER_STATE["config"] = { + "db_path": self.server_db, + "cert_dir": self.server_cert_dir, + "max_seats": 20, + "tcp_host": "127.0.0.1", + "tcp_port": 9443, + "hermes_host": "127.0.0.1", + "hermes_port": 8443, + "server_fingerprint": "FP_TEST_HUB", + "server_name": "Test-Hub", + "license_server_url": "https://logar.eibl.tech" + } + summary = Server.get_license_summary() + self.assertEqual(summary["max_seats"], 20) + + # 5. Authority increments seats by +15 on renewal (total 35) + with open(os.path.join(self.server_cert_dir, "ca.crt"), "r", encoding="utf-8") as f: + current_ca_pem = f.read() + + renewed = authority.renew_license_cert( + current_cert_pem=current_ca_pem, + seat_increment=15, + db_path=self.db_path, + cert_dir=self.master_ca_dir + ) + self.assertEqual(renewed["seats"], 35) + + # 6. Server processes the renewed certificate and saves it to ca.crt + ca_path = os.path.join(self.server_cert_dir, "ca.crt") + with open(ca_path, "w", encoding="utf-8") as f: + f.write(renewed["ca_cert"]) + + new_info = enrollment.extract_license_info_from_cert(renewed["ca_cert"]) + self.assertEqual(new_info["seats"], 35) + + # Server updates DB and config + Server.SERVER_STATE["config"]["max_seats"] = new_info["seats"] + conn = sqlite3.connect(self.server_db) + conn.execute("UPDATE license_config SET max_seats = ? WHERE id = 1", (new_info["seats"],)) + conn.commit() + conn.close() + + summary_renewed = Server.get_license_summary() + self.assertEqual(summary_renewed["max_seats"], 35) + def test_webui_rendering(self): """Verifies that the WebUI HTML contains key components, stats, and download triggers.""" Server.init_db(self.server_db, max_seats=10) @@ -220,8 +296,8 @@ class TestLicenseAuthorityAndWebUI(unittest.TestCase): html = response.body.decode("utf-8") self.assertIn("LOGAR Fleet Hub & License Management", html.replace("&", "&")) self.assertIn("Export .lic Request", html) - self.assertIn("Import & Activate Signed CA Certificate", html.replace("&", "&")) - self.assertIn("Renew via mTLS Now", html) + self.assertIn("Import License (.lic / ca.crt)", html) + self.assertIn("Sync & Renew via mTLS", html.replace("&", "&")) self.assertIn("logar.eibl.tech", html)