| 3031 | } |
| 3032 | |
| 3033 | fn resolve_supervisor_bin_source( |
| 3034 | docker_config: &DockerComputeConfig, |
| 3035 | current_exe: Option<&Path>, |
| 3036 | target_candidates: &[PathBuf], |
| 3037 | ) -> CoreResult<SupervisorBinSource> { |
| 3038 | // Tier 1: explicit supervisor_bin in [openshell.drivers.docker]. |
| 3039 | if let Some(path) = docker_config.supervisor_bin.clone() { |
| 3040 | let path = canonicalize_existing_file(&path, "docker supervisor binary")?; |
| 3041 | validate_linux_elf_binary(&path)?; |
| 3042 | return Ok(SupervisorBinSource::Binary(path)); |
| 3043 | } |
| 3044 | |
| 3045 | // Tier 2: explicit supervisor_image in [openshell.drivers.docker]. |
| 3046 | // A configured image should be the source of truth even when a local |
| 3047 | // developer build is present under target/. |
| 3048 | if let Some(image) = docker_config.supervisor_image.clone() { |
| 3049 | return Ok(SupervisorBinSource::Image(image)); |
| 3050 | } |
| 3051 | |
| 3052 | // Tier 3: sibling `openshell-sandbox` next to the running gateway |
| 3053 | // (release artifact layout). Linux-only because the sibling must be a |
| 3054 | // Linux ELF to bind-mount into a Linux container. |
| 3055 | if cfg!(target_os = "linux") |
| 3056 | && let Some(current_exe) = current_exe |
| 3057 | && let Some(parent) = current_exe.parent() |
| 3058 | { |
| 3059 | let sibling = parent.join("openshell-sandbox"); |
| 3060 | if sibling.is_file() { |
| 3061 | let path = canonicalize_existing_file(&sibling, "docker supervisor binary")?; |
| 3062 | if validate_linux_elf_binary(&path).is_ok() { |
| 3063 | return Ok(SupervisorBinSource::Binary(path)); |
| 3064 | } |
| 3065 | } |
| 3066 | } |
| 3067 | |
| 3068 | // Tier 4: local cargo target build (developer workflow). Preferred |
| 3069 | // over the default registry image when available because it matches |
| 3070 | // whatever the developer just built. |
| 3071 | for candidate in target_candidates { |
| 3072 | if candidate.is_file() { |
| 3073 | let path = canonicalize_existing_file(candidate, "docker supervisor binary")?; |
| 3074 | if validate_linux_elf_binary(&path).is_ok() { |
| 3075 | return Ok(SupervisorBinSource::Binary(path)); |
| 3076 | } |
| 3077 | } |
| 3078 | } |
| 3079 | |
| 3080 | // Tier 5: pull the release-matched default supervisor image and extract |
| 3081 | // the binary to a host-side cache keyed by image content digest. |
| 3082 | Ok(SupervisorBinSource::Image(default_docker_supervisor_image())) |
| 3083 | } |
| 3084 | |
| 3085 | pub(crate) async fn resolve_supervisor_bin( |
| 3086 | docker: &Docker, |