fix(installer): make curl|bash invocation safe + fetch missing bundle #9

Merged
MillasAgent merged 1 commit from fix/curl-bash-stdin into main 2026-09-04 15:01:30 +00:00
Owner

Resumen

Fix de Forgejo Issue #5: install.sh y openmillas crasheaban con BASH_SOURCE[0]: variable sin asignar cuando se invocaban vía curl ... | bash, rompiendo la UX documentada de instalación en una línea.

Aplica la Opción A del issue verbatim (el chequeo de 4 partes sobre BASH_SOURCE[0]) más el fallback de fetch del bundle que el issue implica: cuando BUNDLE_DIR está vacío, cmd_install descarga el bundle a un mktemp -d y lo usa desde ahí.

Cambios (5 ficheros)

Fichero Cambio
workspace/opencode/install.sh SCRIPT_DIR fix + tolerant source line + fetch_bundle_to_tmpdir helper + cmd_install head (fetch-on-empty) + hardening del filename allowlist
workspace/opencode/openmillas SCRIPT_DIR fix verbatim del issue (línea 21)
workspace/opencode/tests/test_install.sh do_test_install_curl_pipe_stdin (regression test, sin red; usa bash <(cat install.sh) --help)
CHANGELOG.md Entrada §Fixed cerrando Forgejo Issue #5
AGENTS.md Versión 0.3.10.3.2

Diff stats

 AGENTS.md                                |  2 +-
 CHANGELOG.md                             |  2 +
 workspace/opencode/install.sh            | 92 ++++++++++++++++++++++++++++++--
 workspace/opencode/openmillas            |  8 ++-
 workspace/opencode/tests/test_install.sh | 47 +++++++++++++++-
 5 files changed, 143 insertions(+), 8 deletions(-)

Spec

Diseño documentado en .internal/specs/fix-curl-bash-stdin.md (gitignored). El spec incluye las 2 correcciones a medio camino que el test suite cazó en vivo:

  1. BUNDLE_DIR="${BUNDLE_DIR:-$SCRIPT_DIR}" (no :$SCRIPT_DIR:"") — el segundo dropeaba el path in-tree y rompía 10 tests existentes.
  2. local base="${REMOTE_RAW_BASE}/workspace/opencode"REMOTE_RAW_BASE apunta a la raíz del repo, no al subdir del bundle.

Ambas detectadas por el suite de tests, no por asunción (L-036 aplicado al pie de la letra: la issue es hipótesis, el código es evidencia).

Validación

  • bash workspace/opencode/deploy.sh --check — verde
  • bash workspace/opencode/tests/test_install.sh27/27 PASS (26 existentes + nuevo regression test)
  • bash workspace/opencode/tests/test_internal.sh — ALL PASS
  • bash <(cat workspace/opencode/install.sh) --help (smoke stdin) — exit 0, sin BASH_SOURCE[0]: variable sin asignar
  • bash workspace/opencode/install.sh --yes --no-interaction (smoke in-tree) — exit 0, install completo
  • security-auditorGREEN (tras aplicar los 2 findings: filename allowlist + test cleanup)
  • arch-quality-reviewerGREEN

Aplicación de L-036

Este fix es el segundo caso de uso del meta-aprendizaje L-036 (issue handling discipline). El spec ya advertía (en la sección "Discrepancy this spec must resolve") de que la Opción A del issue sola no bastaba por culpa del ordering entre SCRIPT_DIR, source y BUNDLE_DIR. La implementación añadió las 2 correcciones; el suite de tests las cazó al vuelo. Sin la disciplina de spec+test-driven, las 2 regresiones habrían llegado a PR.

Out of scope (deliberado, documentado en el spec)

  • TD-20 (sha256 pin para curl|bash): deferred por el usuario. El nuevo fetch hace del bundle remoto un input de code-execution activo sin verificación; TD-20 lo cubre repo-wide.
  • cmd_update self-update path ($REMOTE_RAW_BASE/install.sh sin prefijo workspace/opencode/): bug latente con la misma causa raíz; necesita issue separado.

Closes #5

## Resumen Fix de Forgejo Issue #5: `install.sh` y `openmillas` crasheaban con `BASH_SOURCE[0]: variable sin asignar` cuando se invocaban vía `curl ... | bash`, rompiendo la UX documentada de instalación en una línea. Aplica la **Opción A del issue verbatim** (el chequeo de 4 partes sobre `BASH_SOURCE[0]`) más el fallback de fetch del bundle que el issue implica: cuando `BUNDLE_DIR` está vacío, `cmd_install` descarga el bundle a un `mktemp -d` y lo usa desde ahí. ### Cambios (5 ficheros) | Fichero | Cambio | |---|---| | `workspace/opencode/install.sh` | SCRIPT_DIR fix + tolerant source line + `fetch_bundle_to_tmpdir` helper + `cmd_install` head (fetch-on-empty) + hardening del filename allowlist | | `workspace/opencode/openmillas` | SCRIPT_DIR fix verbatim del issue (línea 21) | | `workspace/opencode/tests/test_install.sh` | `do_test_install_curl_pipe_stdin` (regression test, sin red; usa `bash <(cat install.sh) --help`) | | `CHANGELOG.md` | Entrada §Fixed cerrando Forgejo Issue #5 | | `AGENTS.md` | Versión `0.3.1` → `0.3.2` | ### Diff stats ``` AGENTS.md | 2 +- CHANGELOG.md | 2 + workspace/opencode/install.sh | 92 ++++++++++++++++++++++++++++++-- workspace/opencode/openmillas | 8 ++- workspace/opencode/tests/test_install.sh | 47 +++++++++++++++- 5 files changed, 143 insertions(+), 8 deletions(-) ``` ### Spec Diseño documentado en `.internal/specs/fix-curl-bash-stdin.md` (gitignored). El spec incluye las 2 correcciones a medio camino que el test suite cazó en vivo: 1. **`BUNDLE_DIR="${BUNDLE_DIR:-$SCRIPT_DIR}"`** (no `:$SCRIPT_DIR` → `:""`) — el segundo dropeaba el path in-tree y rompía 10 tests existentes. 2. **`local base="${REMOTE_RAW_BASE}/workspace/opencode"`** — `REMOTE_RAW_BASE` apunta a la raíz del repo, no al subdir del bundle. Ambas detectadas por el suite de tests, **no por asunción** (L-036 aplicado al pie de la letra: la issue es hipótesis, el código es evidencia). ### Validación - ✅ `bash workspace/opencode/deploy.sh --check` — verde - ✅ `bash workspace/opencode/tests/test_install.sh` — **27/27 PASS** (26 existentes + nuevo regression test) - ✅ `bash workspace/opencode/tests/test_internal.sh` — ALL PASS - ✅ `bash <(cat workspace/opencode/install.sh) --help` (smoke stdin) — exit 0, sin `BASH_SOURCE[0]: variable sin asignar` - ✅ `bash workspace/opencode/install.sh --yes --no-interaction` (smoke in-tree) — exit 0, install completo - ✅ `security-auditor` — **GREEN** (tras aplicar los 2 findings: filename allowlist + test cleanup) - ✅ `arch-quality-reviewer` — **GREEN** ### Aplicación de L-036 Este fix es el segundo caso de uso del meta-aprendizaje L-036 (issue handling discipline). El spec ya advertía (en la sección "Discrepancy this spec must resolve") de que la Opción A del issue sola no bastaba por culpa del ordering entre `SCRIPT_DIR`, `source` y `BUNDLE_DIR`. La implementación añadió las 2 correcciones; el suite de tests las cazó al vuelo. Sin la disciplina de spec+test-driven, las 2 regresiones habrían llegado a PR. ### Out of scope (deliberado, documentado en el spec) - **TD-20** (sha256 pin para curl|bash): deferred por el usuario. El nuevo fetch hace del bundle remoto un input de code-execution activo sin verificación; TD-20 lo cubre repo-wide. - **`cmd_update` self-update path** (`$REMOTE_RAW_BASE/install.sh` sin prefijo `workspace/opencode/`): bug latente con la misma causa raíz; necesita issue separado. --- Closes #5
Resolves Forgejo Issue #5: stdin-sourced install.sh / openmillas no
longer crash with 'BASH_SOURCE[0]: variable sin asignar'. The documented
one-line install UX (curl ... | bash) now works end-to-end.

Implements the verbatim Issue #5 Option A (the 4-part BASH_SOURCE[0]
check) in install.sh and openmillas, plus a fetch_bundle_to_tmpdir
helper that cmd_install calls when BUNDLE_DIR is empty (curl|bash case).
The helper uses mktemp -d + Forgejo API directory listings to populate
the bundle in a tmp dir.

Spec: .internal/specs/fix-curl-bash-stdin.md

Validation:
- deploy.sh --check: verde
- test_install.sh: 27/27 PASS (26 existing + new do_test_install_curl_pipe_stdin)
- test_internal.sh: ALL PASS
- security-auditor: GREEN after applying findings (allowlist + test cleanup)
- arch-quality-reviewer: GREEN

Mid-implementation corrections caught by the test suite (L-036 in
action — the issue was a hypothesis, the test was the evidence):
  (a) BUNDLE_DIR default must include ':$SCRIPT_DIR' fallback for
      in-tree runs; dropping it made cmd_install try to fetch from
      $REMOTE_RAW_BASE/lib/jsonc.sh (404) when running from a checkout.
  (b) fetch_bundle_to_tmpdir must prefix the URL with
      'workspace/opencode' since REMOTE_RAW_BASE points to repo root.

Follow-up hardening from security-auditor (Medium + Low):
  - Allowlist filenames returned by the Forgejo API against
    ^[A-Za-z0-9._-]+$ before curl/write (defense-in-depth, even
    though basename already strips ../).
  - Test no longer spawns openmillas in the background; invokes
    inline with stdin=/dev/null so no zombie is left behind.

Bumps OPENMILLAS_VERSION 0.3.1 → 0.3.2 in install.sh, openmillas,
AGENTS.md §1 version line. CHANGELOG §Fixed entry closes Forgejo #5.

Deferred (out of scope, documented as adjacent concern):
  - TD-20 (sha256 pin for curl|bash): deferred by the user; the new
    fallback makes the unverified bundle fetch an active code-execution
    input, but TD-20 covers it repo-wide.
  - cmd_update's '$REMOTE_RAW_BASE/install.sh' path (install.sh:621,
    openmillas:354) — same root cause as the original Issue #5 bug;
    would need its own issue.

Closes #5
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MillasDev/memory!9
No description provided.