(tmp_path, self_signed_application_certificate_macos)
| 954 | @pytest.mark.skipif(not shutil.which("xcodebuild"), reason="requires xcodebuild") |
| 955 | @pytest.mark.skipif("CI" not in os.environ, reason="CI only") |
| 956 | def test_macos_signing(tmp_path, self_signed_application_certificate_macos): |
| 957 | try: |
| 958 | subprocess.run(["xcodebuild", "--help"], check=True, capture_output=True) |
| 959 | except subprocess.CalledProcessError: |
| 960 | pytest.skip("xcodebuild requires XCode to compile extra pages.") |
| 961 | input_path = tmp_path / "input" |
| 962 | recipe_path = _example_path("osxpkg_extra_pages") |
| 963 | shutil.copytree(str(recipe_path), str(input_path)) |
| 964 | with open(input_path / "construct.yaml", "a") as f: |
| 965 | f.write(f"notarization_identity_name: {self_signed_application_certificate_macos}\n") |
| 966 | output_path = tmp_path / "output" |
| 967 | installer, _ = next(create_installer(input_path, output_path)) |
| 968 | |
| 969 | # Check component signatures |
| 970 | expanded_path = output_path / "expanded" |
| 971 | # expand-full is an undocumented option that extracts all archives, |
| 972 | # including binary archives like the PlugIns file |
| 973 | cmd = ["pkgutil", "--expand-full", installer, expanded_path] |
| 974 | _execute(cmd) |
| 975 | conda_exe_name = format_conda_exe_name(CONSTRUCTOR_CONDA_EXE) |
| 976 | components = [ |
| 977 | Path(expanded_path, "prepare_installation.pkg", "Payload", "osx-pkg-test", conda_exe_name), |
| 978 | Path(expanded_path, "Plugins", "ExtraPage.bundle"), |
| 979 | ] |
| 980 | internal_dir = Path( |
| 981 | expanded_path, "prepare_installation.pkg", "Payload", "osx-pkg-test", "_internal" |
| 982 | ) |
| 983 | components.extend([file for file in internal_dir.glob("**") if is_macho_binary(file)]) |
| 984 | validated_signatures = [] |
| 985 | for component in components: |
| 986 | p = subprocess.run( |
| 987 | ["/usr/bin/codesign", "--verify", str(component), "--verbose=4"], |
| 988 | check=True, |
| 989 | text=True, |
| 990 | capture_output=True, |
| 991 | ) |
| 992 | # codesign --verify outputs to stderr |
| 993 | lines = p.stderr.split("\n")[:-1] |
| 994 | if ( |
| 995 | len(lines) == 2 |
| 996 | and lines[0] == f"{component}: valid on disk" |
| 997 | and lines[1] == f"{component}: satisfies its Designated Requirement" |
| 998 | ): |
| 999 | validated_signatures.append(component) |
| 1000 | assert validated_signatures == components |
| 1001 | |
| 1002 | |
| 1003 | def test_example_scripts(tmp_path, request): |
nothing calls this directly
no test coverage detected