From ea586be6af8d2ff3c35404dbc59cec7a0135784d Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Mon, 27 Nov 2023 12:26:27 -0800 Subject: [PATCH] ci: Disable sandboxing by default The ~/Applications/DkMLNative is not a path added to the predefined OCaml sandbox, and more importantly the user can change the installation path to anything. So [ocaml] and related executables can't be found in the sandbox. +bugfix: Recursively delete the temp dir Part of https://github.com/diskuv/dkml-installer-ocaml/issues/80 --- src/dkml-exe/cmd_init.ml | 16 +++++- src/dkml-exe/dkml_exe_lib.ml | 3 +- src/runtimelib/dkml_runtimelib.mli | 1 + src/runtimelib/init_system.ml | 90 ++++++++++++++++++++---------- src/with-dkml/with_dkml.ml | 7 ++- 5 files changed, 82 insertions(+), 35 deletions(-) diff --git a/src/dkml-exe/cmd_init.ml b/src/dkml-exe/cmd_init.ml index 9e0e321..d75c9fb 100644 --- a/src/dkml-exe/cmd_init.ml +++ b/src/dkml-exe/cmd_init.ml @@ -24,6 +24,15 @@ let enable_imprecise_c99_float_ops_t = in Arg.(value & flag & info [ "enable-imprecise-c99-float-ops" ] ~doc) +let disable_sandboxing_t = + let doc = + "Disables the creation of sandboxes during `opam install` commands. Poorly \ + written or malicious opam packages may erase or modify files on your \ + macOS and Linux machines. Ignored for Windows and all other non-macOS and \ + non-Linux machines." + in + Arg.(value & flag & info [ "disable-sandboxing" ] ~doc) + let non_system_opt = "non-system-compiler" let non_system_compiler_t = @@ -106,10 +115,11 @@ let create_local_switch ~system_cfg ~scripts_dir_fp ~yes ~non_system_compiler Ok (128 + signal) let run f_setup localdir_fp_opt yes non_system_compiler system_only - enable_imprecise_c99_float_ops = + enable_imprecise_c99_float_ops disable_sandboxing = let enable_imprecise_c99_float_ops = if enable_imprecise_c99_float_ops then Some () else None in + let disable_sandboxing = if disable_sandboxing then Some () else None in f_setup () >>= fun () -> OS.Dir.with_tmp "dkml-initsystem-de-%s" (* de = dkml-exe *) (fun dir_fp () -> @@ -146,8 +156,8 @@ let run f_setup localdir_fp_opt yes non_system_compiler system_only ignore temp_dir; Ok system_cfg in - Dkml_runtimelib.init_system ?enable_imprecise_c99_float_ops ~f_temp_dir - ~f_system_cfg () + Dkml_runtimelib.init_system ?enable_imprecise_c99_float_ops + ?disable_sandboxing ~f_temp_dir ~f_system_cfg () >>= fun ec -> if ec <> 0 then exit ec; (* Create local switch *) diff --git a/src/dkml-exe/dkml_exe_lib.ml b/src/dkml-exe/dkml_exe_lib.ml index b60cde1..d97f364 100644 --- a/src/dkml-exe/dkml_exe_lib.ml +++ b/src/dkml-exe/dkml_exe_lib.ml @@ -69,7 +69,8 @@ let init_t = const rresult_to_term_result $ (const Cmd_init.run $ const setup $ localdir_opt_t $ yes_t $ Cmd_init.non_system_compiler_t $ Cmd_init.system_only_t - $ Cmd_init.enable_imprecise_c99_float_ops_t)) + $ Cmd_init.enable_imprecise_c99_float_ops_t + $ Cmd_init.disable_sandboxing_t)) let init_info = Cmd.info diff --git a/src/runtimelib/dkml_runtimelib.mli b/src/runtimelib/dkml_runtimelib.mli index df302f9..f63a1b8 100644 --- a/src/runtimelib/dkml_runtimelib.mli +++ b/src/runtimelib/dkml_runtimelib.mli @@ -27,6 +27,7 @@ val get_msys2_create_opam_switch_options : SystemConfig.msys2_t -> string list val init_system : ?enable_imprecise_c99_float_ops:unit -> + ?disable_sandboxing:unit -> ?delete_temp_dir_after_init:unit -> f_temp_dir:(unit -> (Fpath.t, Rresult.R.msg) result) -> f_system_cfg: diff --git a/src/runtimelib/init_system.ml b/src/runtimelib/init_system.ml index a90bab0..6263b82 100644 --- a/src/runtimelib/init_system.ml +++ b/src/runtimelib/init_system.ml @@ -46,13 +46,18 @@ let create_playground_switch ~system_cfg ~ocaml_home_fp ~opamroot_dir_fp = (* Run the command *) run_command cmd rel_fp -let create_opam_root ~opamroot_dir_fp ~ocaml_home_fp ~system_cfg = +let create_opam_root ?disable_sandboxing ?reinit ~opamroot_dir_fp ~ocaml_home_fp + ~system_cfg () = (* Assemble command line arguments *) let open Opam_context.SystemConfig in let* rel_fp = Fpath.of_string "vendor/drd/src/unix/private/init-opam-root.sh" in let init_opam_root_fp = Fpath.(system_cfg.scripts_dir_fp // rel_fp) in + let disable_sandboxing_args = + match disable_sandboxing with Some () -> [ "-x" ] | None -> [] + in + let reinit_args = match reinit with Some () -> [ "-i" ] | None -> [] in let cmd = Cmd.of_list (system_cfg.env_exe_wrapper @@ -67,7 +72,8 @@ let create_opam_root ~opamroot_dir_fp ~ocaml_home_fp ~system_cfg = Fpath.to_string opamroot_dir_fp; "-v"; Fpath.to_string ocaml_home_fp; - ]) + ] + @ disable_sandboxing_args @ reinit_args) in (* Run the command *) run_command cmd rel_fp @@ -130,12 +136,14 @@ let critical_vsstudio_files = type opamroot_status = | Opamroot_missing | Opamroot_no_repository - | Opamroot_complete + | Opamroot_complete_with_sandbox + | Opamroot_complete_without_sandbox let get_opamroot_status () = let* opamroot_dir_fp = Lazy.force Opam_context.get_opam_root in - let* opamroot_exists = OS.File.exists Fpath.(opamroot_dir_fp / "config") in - if opamroot_exists then + let config = Fpath.(opamroot_dir_fp / "config") in + let* config_exists = OS.File.exists config in + if config_exists then let* dkml_version = Lazy.force Dkml_context.get_dkmlversion_or_default in (* COMPLETE: The diskuv- repository must exist *) let* diskuv_repo = @@ -149,8 +157,23 @@ let get_opamroot_status () = opamroot_dir_fp / "repo" / Printf.sprintf "diskuv-%s.tar.gz" dkml_version) in + (* Does /config have: + wrap-build-commands: + ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} + wrap-install-commands: + ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} + wrap-remove-commands: + ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} + *) + let* config_contents = OS.File.read config in + let config_contains_sandbox = + Astring.String.find_sub ~sub:"%{hooks}%/sandbox.sh" config_contents + |> Option.is_some + in let state = - if diskuv_repo || diskuv_repo_targz then Opamroot_complete + if diskuv_repo || diskuv_repo_targz then + if config_contains_sandbox then Opamroot_complete_with_sandbox + else Opamroot_complete_without_sandbox else Opamroot_no_repository in Ok state @@ -214,8 +237,8 @@ let verify_git ~msg_why_check_git ~what_install = git') to install it.") else Ok () -let init_system_helper ?enable_imprecise_c99_float_ops ~f_system_cfg ~temp_dir - () = +let init_system_helper ?enable_imprecise_c99_float_ops ?disable_sandboxing + ~f_system_cfg ~temp_dir () = (* DEVELOPER NOTE: @@ -278,26 +301,35 @@ let init_system_helper ?enable_imprecise_c99_float_ops ~f_system_cfg ~temp_dir let* ec = let what_install = "\"opam root\" package cache" in match opamroot_status with - | Opamroot_complete -> Ok 0 - | Opamroot_missing -> - let msg_why = - "Detected that the \"opam root\" package cache is not present." - in - let* () = verify_git ~msg_why_check_git:msg_why ~what_install in - Logs.warn (fun l -> - l "%s Creating it now. ETA: 10 minutes." msg_why); - let* system_cfg = Lazy.force system_cfg in - create_opam_root ~opamroot_dir_fp ~ocaml_home_fp ~system_cfg - | Opamroot_no_repository -> - let msg_why = - "Detected that the \"opam root\" package cache is missing the \ - DkML repository." + | Opamroot_complete_without_sandbox -> Ok 0 + | Opamroot_complete_with_sandbox when disable_sandboxing = None -> + Ok 0 + | Opamroot_missing | Opamroot_no_repository + | Opamroot_complete_with_sandbox -> + let msg_why, action, reinit = + match opamroot_status with + | Opamroot_no_repository -> + ( "Detected that the \"opam root\" package cache is \ + missing the DkML repository.", + "Creating it", + None ) + | Opamroot_complete_with_sandbox -> + ( "Detected that the \"opam root\" package cache is \ + configured for sandboxing.", + "Disabling sandboxing", + Some () ) + | _ -> + ( "Detected that the \"opam root\" package cache is not \ + present.", + "Creating it", + None ) in let* () = verify_git ~msg_why_check_git:msg_why ~what_install in Logs.warn (fun l -> - l "%s Creating it now. ETA: 10 minutes." msg_why); + l "%s %s now. ETA: 10 minutes." msg_why action); let* system_cfg = Lazy.force system_cfg in - create_opam_root ~opamroot_dir_fp ~ocaml_home_fp ~system_cfg + create_opam_root ?disable_sandboxing ?reinit ~opamroot_dir_fp + ~ocaml_home_fp ~system_cfg () in if ec <> 0 then Ok ec (* short-circuit exit if signal raised *) else @@ -316,15 +348,15 @@ let init_system_helper ?enable_imprecise_c99_float_ops ~f_system_cfg ~temp_dir let* system_cfg = Lazy.force system_cfg in create_playground_switch ~opamroot_dir_fp ~ocaml_home_fp ~system_cfg) -let init_system ?enable_imprecise_c99_float_ops ?delete_temp_dir_after_init - ~f_temp_dir ~f_system_cfg () = +let init_system ?enable_imprecise_c99_float_ops ?disable_sandboxing + ?delete_temp_dir_after_init ~f_temp_dir ~f_system_cfg () = let* temp_dir = f_temp_dir () in let delayed_error = ref (Ok 0) in let* ec = Fun.protect ~finally:(fun () -> if Option.is_some delete_temp_dir_after_init then - match OS.Dir.delete temp_dir with + match OS.Dir.delete ~recurse:true temp_dir with | Ok () -> () | Error (`Msg msg) -> ( match !delayed_error with @@ -340,7 +372,7 @@ let init_system ?enable_imprecise_c99_float_ops ?delete_temp_dir_after_init Fpath.pp temp_dir msg))) (fun () -> let* (_created : bool) = OS.Dir.create temp_dir in - init_system_helper ?enable_imprecise_c99_float_ops ~f_system_cfg - ~temp_dir ()) + init_system_helper ?enable_imprecise_c99_float_ops ?disable_sandboxing + ~f_system_cfg ~temp_dir ()) in match !delayed_error with Ok _ -> Ok ec | Error e -> Error e diff --git a/src/with-dkml/with_dkml.ml b/src/with-dkml/with_dkml.ml index 62cb519..f4b544c 100644 --- a/src/with-dkml/with_dkml.ml +++ b/src/with-dkml/with_dkml.ml @@ -607,8 +607,11 @@ let main_with_result () = (* Now we finish gathering information to create switches *) Dkml_runtimelib.SystemConfig.create ~scripts_dir_fp () in - Dkml_runtimelib.init_system ~delete_temp_dir_after_init:() ~f_temp_dir - ~f_system_cfg () + (* By default we disable sandboxing so that macOS/Unix actually work + out-of-the-box. If the user wants something different, they + can do [dkml init --system ] before. *) + Dkml_runtimelib.init_system ~disable_sandboxing:() + ~delete_temp_dir_after_init:() ~f_temp_dir ~f_system_cfg () >>= fun ec -> if ec <> 0 then exit ec; (* EIGHTH, stop tracing variables from propagating. *)