Skip to content

chore(bash32): guard declare -A callers + route dream-cli validate through $BASH#1011

Draft
yasinBursali wants to merge 1 commit intoLight-Heart-Labs:mainfrom
yasinBursali:chore/bash32-declare-a-audit
Draft

chore(bash32): guard declare -A callers + route dream-cli validate through $BASH#1011
yasinBursali wants to merge 1 commit intoLight-Heart-Labs:mainfrom
yasinBursali:chore/bash32-declare-a-audit

Conversation

@yasinBursali
Copy link
Copy Markdown
Contributor

What

Adds Bash 4+ guards to five scripts that use declare -A without one, and routes two dream config validate subprocesses through "$BASH" so they inherit dream-cli's modern bash interpreter.

Files touched (6):

  • dream-server/scripts/pre-download.sh — Pattern A guard (bare exit 1)
  • dream-server/scripts/dream-test-functional.sh — Pattern A guard + drop dead 2>/dev/null || true fallback on declare -A SERVICE_PORTS
  • dream-server/scripts/validate-env.sh — Pattern A guard
  • dream-server/lib/progress.sh — Pattern B guard (return 1 2>/dev/null || exit 1)
  • dream-server/installers/phases/03-features.sh — Pattern B guard
  • dream-server/dream-cli — prefix validate-env.sh and validate-manifests.sh subprocess execs with "$BASH"

Guard style mirrors dream-cli:8-14 (Pattern A, standalone scripts) and lib/service-registry.sh:18-24 (Pattern B, sourced libraries).

Why

On macOS, system /bin/bash is 3.2.57, which does not support associative arrays. Two user-facing problems:

  1. Invoking any of these scripts directly under system bash (e.g. ./scripts/pre-download.sh --tier 3 from FAQ.md) produced a cryptic declare -A: invalid option crash with no actionable hint.
  2. Even when dream-cli itself was launched under a modern Homebrew bash (its own Bash 4+ guard passes), it invoked scripts/validate-env.sh via shebang — which re-resolves to /bin/bash 3.2 regardless of the parent interpreter. dream config validate was silently non-functional on macOS for users without bash in PATH.

Guards turn (1) into a friendly error with a brew install bash hint. The "$BASH" prefix makes (2) work by inheriting the parent interpreter.

How

  • Guard block placed after the file header/purpose comments but before set -euo pipefail and before the first declare -A. Pattern B uses return 1 2>/dev/null || exit 1 so sourced-vs-exec'd-direct both behave correctly.
  • dream-cli:1117 and :1125: "$INSTALL_DIR/scripts/<script>.sh" ..."$BASH" "$INSTALL_DIR/scripts/<script>.sh" .... $BASH is bash's own path to its interpreter; since dream-cli guards at line 9 require Bash 4+, $BASH is guaranteed to point at a modern bash when this code runs.

Testing

  • bash -n syntax check — all 6 files pass
  • shellcheck — per-file warning counts identical between upstream/main and PR (no new diagnostics). SC2317 on Pattern B exit 1 is accepted baseline, identical to service-registry.sh:23.
  • make lint — clean
  • Pre-commit (gitleaks / private-key / large-file) — clean
  • Live macOS test on Bash 3.2.57: each script exits with "ERROR: ... requires Bash 4.0+ (you have 3.2.57)" when run under /bin/bash. Pattern B sourced-path correctly propagates non-zero $? to the caller without aborting the parent shell.
  • Pattern B error-text wording aligned to lib/service-registry.sh:20 ("Install a modern version") for consistency.

Platform Impact

  • macOS (primary target): dream config validate now works without requiring the user to manually invoke via /opt/homebrew/bin/bash. Direct invocations of the 5 scripts under system bash produce a clean error message instead of a cryptic crash.
  • Linux: no impact (Bash 5+ everywhere; guards never fire).
  • Windows WSL2: no impact (Bash 5+ in WSL2; guards never fire).

…rough $BASH

Five scripts used declare -A (bash 4+ associative arrays) without the
safety net already present in dream-cli and lib/service-registry.sh:

- scripts/pre-download.sh (user-invoked per FAQ.md)
- scripts/dream-test-functional.sh (dev/test tool)
- scripts/validate-env.sh (invoked by dream config validate)
- lib/progress.sh (sourced by install-core.sh)
- installers/phases/03-features.sh (sourced by install-core.sh)

On macOS the system /bin/bash is 3.2.57 and declare -A fails with a
cryptic "invalid option" error. Pattern A guards (standalone scripts)
use bare exit 1; Pattern B guards (sourced libs) use
"return 1 2>/dev/null || exit 1", matching the accepted patterns in
dream-cli:8-14 and lib/service-registry.sh:18-24.

Also makes dream config validate functional on macOS by invoking the
sibling subprocesses through "$BASH", so the modern bash that dream-cli
is running under is inherited by validate-env.sh and validate-manifests.sh
rather than being re-resolved through their #!/bin/bash shebang.

Removes a dead "2>/dev/null || true" fallback on declare -A SERVICE_PORTS
in dream-test-functional.sh; surrounding set -e + the service-registry
guard already abort the script before that line under bash 3.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@yasinBursali yasinBursali marked this pull request as draft April 23, 2026 22:28
@yasinBursali
Copy link
Copy Markdown
Contributor Author

Marked as draft pending merge of #994.

This PR overlaps with open PR #994 (fix/dream-cli-config-security-macos):

Once #994 lands, I'll rebase this branch; the duplicate changes will drop automatically and the remaining scope is:

Will un-draft and request review after the post-#994 rebase is clean.

@Lightheartdevs
Copy link
Copy Markdown
Collaborator

Audit follow-up: keep draft and rebase after the strict-mode foundations.

The Bash 4 compatibility guard direction is reasonable, but this branch overlaps with the strict-mode/pipefail stack that has now partially landed. Please rebase on current main, keep only the unique Bash 3.2 compatibility changes, and rerun the relevant shell/BATS coverage before marking ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants