import os import sys import unittest from unittest import mock sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "api")) class TestSigningSecurity(unittest.TestCase): @mock.patch("signing.subprocess.run") @mock.patch("signing._make_temp_file") def test_pin_not_in_cli_args(self, mock_mkstemp, mock_run): """PIN must NOT appear in subprocess command-line args.""" mock_mkstemp.return_value = "/tmp/test_file" mock_run.return_value = mock.MagicMock(returncode=0) import signing signing.sign_tbs_with_yk(b"\x00" * 100, "test-pin-123") cmd = mock_run.call_args[0][0] self.assertNotIn("test-pin-123", cmd, "PIN must not appear in command args") self.assertIn("--pin-source", cmd) self.assertIn("stdin", cmd) self.assertNotIn("--pin", cmd) or cmd.index("--pin-source") < cmd.index("--pin") @mock.patch("signing.subprocess.run") def test_temp_files_use_mkstemp(self, mock_run): """Temp files must use mkstemp, not predictable names.""" mock_run.return_value = mock.MagicMock(returncode=0) with mock.patch("signing.tempfile.mkstemp") as mock_mkstemp: mock_mkstemp.return_value = (0, "/tmp/unpredictable_name") import signing try: signing.sign_tbs_with_yk(b"\x00" * 100, "pin") except Exception: pass calls = [c[0][1] for c in mock_mkstemp.call_args_list] self.assertTrue(all("/tmp/unpredictable_name" in c for c in calls), "All temp files should use mkstemp") def test_no_hardcoded_pin_default(self): """YK PIN must fail if env var not set.""" os.environ.pop("YK_ROOT_PIN", None) os.environ.pop("YK_INT_PIN", None) if "config" in sys.modules: del sys.modules["config"] with self.assertRaises(RuntimeError): __import__("config") if __name__ == "__main__": unittest.main()