From 0c8149d2b155433ceacfb76acd049e7399591666 Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Wed, 22 Apr 2026 19:48:51 -0400 Subject: [PATCH 1/2] fix(sandbox): force executable bit on host_files copied into bin/ The GitHub Contents API (used by admin install) commits all files as 100644, so scripts like scan-unicode lose their executable bit in the .fullsend repo. When bootstrapEnv() copies these into the sandbox via SCP, they remain non-executable and `test -x` fails. Work around this by forcing chmod +x on any host_file whose destination is under a bin/ directory. This is a stopgap until admin install preserves the git tree mode (see #312). Fixes: appdumpster/test-repo#13 review failure Co-Authored-By: Claude Opus 4.6 --- internal/cli/run.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/cli/run.go b/internal/cli/run.go index 3686b56fd7..358e4f4508 100644 --- a/internal/cli/run.go +++ b/internal/cli/run.go @@ -651,6 +651,18 @@ func bootstrapEnv(sshConfigPath, sandboxName, repoDir string, h *harness.Harness return fmt.Errorf("copying host file %s to %s: %w", hf.Src, hf.Dest, err) } } + + // TODO(#312): remove this once admin install preserves the executable + // bit when writing files to .fullsend/. The GitHub Contents API commits + // everything as 100644, so scripts lose +x. Force it back for anything + // landing in a bin/ directory. + // https://github.com/fullsend-ai/fullsend/issues/312#issuecomment-4300729520 + if strings.Contains(hf.Dest, "/bin/") { + chmodCmd := fmt.Sprintf("chmod +x %s", hf.Dest) + if _, _, _, sshErr := sandbox.SSH(sshConfigPath, sandboxName, chmodCmd, 10*time.Second); sshErr != nil { + return fmt.Errorf("chmod host file %s in sandbox: %w", hf.Dest, sshErr) + } + } } return nil From b5089b98f0f97b5f5412ee4e0f131e194fb9169c Mon Sep 17 00:00:00 2001 From: Ralph Bean Date: Wed, 22 Apr 2026 20:16:32 -0400 Subject: [PATCH 2/2] Fix issue reference Co-authored-by: Ralph Bean --- internal/cli/run.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/cli/run.go b/internal/cli/run.go index 358e4f4508..b8331a53d2 100644 --- a/internal/cli/run.go +++ b/internal/cli/run.go @@ -652,11 +652,11 @@ func bootstrapEnv(sshConfigPath, sandboxName, repoDir string, h *harness.Harness } } - // TODO(#312): remove this once admin install preserves the executable + // TODO(#345): remove this once admin install preserves the executable // bit when writing files to .fullsend/. The GitHub Contents API commits // everything as 100644, so scripts lose +x. Force it back for anything // landing in a bin/ directory. - // https://github.com/fullsend-ai/fullsend/issues/312#issuecomment-4300729520 + // https://github.com/fullsend-ai/fullsend/issues/345#issuecomment-4300740512 if strings.Contains(hf.Dest, "/bin/") { chmodCmd := fmt.Sprintf("chmod +x %s", hf.Dest) if _, _, _, sshErr := sandbox.SSH(sshConfigPath, sandboxName, chmodCmd, 10*time.Second); sshErr != nil {