From bc9d1e564fd1da44e4888daa9ca4e37dd0f19c57 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Sat, 18 Jul 2026 22:12:05 -0700 Subject: [PATCH] fix: stop double-executing git clone / setup hooks via run() run() re-splits its argument as a bare string with no eval, so any call like run "git clone \"$url\" \"$dir\"" corrupts the quoted arguments (embedded escaped quotes survive as literal characters, e.g. git sees the protocol as '"https). Each of the 4 affected call sites papered over this by following run() with a second, correctly quoted manual execution of the same command - meaning every real run double-executed (git clone twice, pip install -e twice, conda env create twice), with the first, corrupted attempt's failure masked by the working second attempt. Fixed by dropping run() at these sites entirely and gating on $dry_run directly with a single, properly quoted real execution path (matches the pattern already used in the new model-cache-redirect extra): - lib/cf-apps.functions: install-cf-app's clone, provision-orchard-node's clone - cf-apps/circuitforge-core.manifest: pip install -e setup hook - cf-apps/kiwi.manifest: conda env create setup hook Verified on sif via a scratch-dir harness (install-cf-app circuitforge-core): first run now clones cleanly with no mangled-URL error, second run correctly skips the clone and re-runs the idempotent pip install; state.conf stays single-entry across both. --- cf-apps/circuitforge-core.manifest | 7 +++++-- cf-apps/kiwi.manifest | 7 +++++-- lib/cf-apps.functions | 22 ++++++++++++---------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/cf-apps/circuitforge-core.manifest b/cf-apps/circuitforge-core.manifest index a7d2862..23e9428 100644 --- a/cf-apps/circuitforge-core.manifest +++ b/cf-apps/circuitforge-core.manifest @@ -13,8 +13,11 @@ app_needs_core=false app_setup_bare_metal() { local dir="$1" - run "conda run -n ${app_conda_env} pip install -e \"${dir}\"" - if [[ $dry_run != true ]]; then + if [[ $dry_run == true ]]; then + boxline "DryRun: conda run -n ${app_conda_env} pip install -e ${dir}" + else + # run() re-splits its argument as a bare string with no eval, which + # mangles the quoted path - execute directly instead. conda run -n "${app_conda_env}" pip install -e "${dir}" fi } diff --git a/cf-apps/kiwi.manifest b/cf-apps/kiwi.manifest index 6198010..35846f4 100644 --- a/cf-apps/kiwi.manifest +++ b/cf-apps/kiwi.manifest @@ -24,8 +24,11 @@ app_setup_docker() { # the docs for the LLM backend choice rather than guessing one. app_setup_bare_metal() { local dir="$1" - run "conda env create -f \"${dir}/environment.yml\" -n \"${app_conda_env}\"" - if [[ $dry_run != true ]]; then + if [[ $dry_run == true ]]; then + boxline "DryRun: conda env create -f ${dir}/environment.yml -n ${app_conda_env}" + else + # run() re-splits its argument as a bare string with no eval, which + # mangles the quoted paths - execute directly instead. conda env create -f "${dir}/environment.yml" -n "${app_conda_env}" fi boxline "${app_name}: conda env '${app_conda_env}' created. See docs/getting-started/installation.md and llm-setup.md for the remaining BYOK LLM backend setup (Ollama/vLLM/OpenAI/Anthropic)." diff --git a/lib/cf-apps.functions b/lib/cf-apps.functions index 150d2b1..d43c0eb 100644 --- a/lib/cf-apps.functions +++ b/lib/cf-apps.functions @@ -181,13 +181,15 @@ install-cf-app() { local clone_dir="${apps_base_dir}/${app_name}" if [ -d "$clone_dir" ]; then warn "${clone_dir} already exists, skipping clone (will not overwrite)" + elif [[ $dry_run == true ]]; then + boxline "DryRun: git clone --recurse-submodules ${repo_url} ${clone_dir}" else + # run() re-splits its argument as a bare string with no eval, which + # mangles anything with embedded quotes (URLs/paths) - execute directly + # instead, gated on $dry_run above rather than double-executing via run(). boxline "Cloning ${app_name} from ${repo_url}" - run "git clone --recurse-submodules \"${repo_url}\" \"${clone_dir}\"" - if [[ $dry_run != true ]]; then - mkdir -p "$apps_base_dir" - git clone --recurse-submodules "$repo_url" "$clone_dir" - fi + mkdir -p "$apps_base_dir" + git clone --recurse-submodules "$repo_url" "$clone_dir" fi if [ -n "$app_env_template" ] && [ -f "${clone_dir}/${app_env_template}" ] && [ ! -f "${clone_dir}/.env" ]; then @@ -260,13 +262,13 @@ provision-orchard-node() { if [ -d "$clone_dir" ]; then warn "${clone_dir} already exists, skipping clone (will not overwrite)" + elif [[ $dry_run == true ]]; then + boxline "DryRun: git clone ${repo_url} ${clone_dir}" else + # See install-cf-app for why this doesn't route through run(). boxline "Cloning circuitforge-orch from Forgejo" - run "git clone \"${repo_url}\" \"${clone_dir}\"" - if [[ $dry_run != true ]]; then - mkdir -p "$apps_base_dir" - git clone "$repo_url" "$clone_dir" - fi + mkdir -p "$apps_base_dir" + git clone "$repo_url" "$clone_dir" fi boxline "Handing off to circuitforge-orch's own install.sh..."