Skip to content

fix: .bashrc merge algorithm corrupted multi-line shell constructs (issue #66)#67

Merged
konard merged 2 commits intomainfrom
issue-66-e55b3c48b549
Mar 6, 2026
Merged

fix: .bashrc merge algorithm corrupted multi-line shell constructs (issue #66)#67
konard merged 2 commits intomainfrom
issue-66-e55b3c48b549

Conversation

@konard
Copy link
Member

@konard konard commented Mar 6, 2026

Fixes #66

Root Cause

When running bash inside an already-running bash session in the sandbox container, bash sources ~/.bashrc and hits a fatal syntax error:

bash: /home/sandbox/.bashrc: line 167: syntax error: unexpected end of file

The error occurs only on explicit bash invocations (not at container start) because .bashrc has an early-return guard:

case $- in *i*) ;; *) return;; esac

entrypoint.sh is non-interactive → returns early, never reaches the broken block. An explicit bash is interactive → executes the full .bashrc → hits the unclosed if.

Root cause: The .bashrc merge algorithm in the Dockerfile used line-level deduplication (grep -qxF "$line"). Since Ubuntu's base .bashrc already contains standalone fi lines (closing its built-in if blocks), the closing fi of the Perlbrew if [ -n "$PS1" ]; then ... fi block was silently deduplicated away, leaving an unclosed if.

Verified with experiments/test-bashrc-merge.sh:

Old algorithm: /tmp/.bashrc-merged: line 57: syntax error: unexpected end of file → bug confirmed

Solution

Fix 1: Section-Header Deduplication

Replace line-level deduplication with section-header deduplication in both Dockerfiles. Each language's .bashrc block starts with a unique # <Tool> configuration comment. The new algorithm:

  • Checks if the section header is already in the base .bashrc
  • If NOT present: appends the header and all subsequent lines (including fi, done, etc.) as a complete unit
  • If present: skips the entire section

This preserves all multi-line shell constructs intact and handles cross-language deduplication correctly (e.g., both java/install.sh and kotlin/install.sh write # SDKMAN configuration — the second is correctly skipped as a whole).

Fix 2: POSIX-Compatible SDKMAN Syntax

Replace [[ -s ... ]] && source with [ -s ... ] && . in SDKMAN .bashrc snippets. Ubuntu's /bin/sh is dash — bash-specific [[ ]] and source would fail if .bashrc is ever sourced from a POSIX shell script.

Files Changed

File Change
Dockerfile Section-header deduplication in bashrc merge RUN step
ubuntu/24.04/full-sandbox/Dockerfile Same fix
ubuntu/24.04/java/install.sh POSIX [ ] and . instead of [[ ]] and source
ubuntu/24.04/kotlin/install.sh Same fix
ubuntu/24.04/full-sandbox/install.sh Same fix

Verification

experiments/test-bashrc-merge-fix.sh — 13/13 tests pass:

  • Old algorithm produces syntax error (bug reproduced ✓)
  • New algorithm produces valid .bashrc (fix confirmed ✓)
  • SDKMAN section appears exactly once (kotlin dedup works ✓)
  • Perlbrew if/fi block is complete and balanced ✓
  • No [[ ]] bash-specific syntax in merged output ✓

Case Study

Full root cause analysis, timeline, and solution in docs/case-studies/issue-66/CASE-STUDY.md.

🤖 Generated with Claude Code

Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: #66
@konard konard self-assigned this Mar 6, 2026
…ssue #66)

Root cause: the line-level deduplication in the Dockerfile merge step treated
every shell line in isolation. Since Ubuntu's base .bashrc already contains
standalone `fi` lines (closing its own if blocks), the closing `fi` from the
Perlbrew `if [ -n "$PS1" ]; then ... fi` block was silently deduplicated away.
This left an unclosed `if` in the merged .bashrc, causing:

  bash: /home/sandbox/.bashrc: line N: syntax error: unexpected end of file

The error appeared only when running `bash` inside the container (not at
container start), because .bashrc has an early-return guard for non-interactive
shells — entrypoint.sh is non-interactive, so it returned before the broken
block; an explicit `bash` invocation is interactive and hit the syntax error.

Fixes:
1. Replace line-level deduplication with section-header deduplication in both
   Dockerfiles. Sections are identified by their unique `# <Tool> configuration`
   comment. If the header already exists in the base, the entire section is
   skipped; otherwise the full section (header + body) is appended intact.
   This preserves all multi-line shell constructs (if/fi, etc.) correctly.

2. Replace bash-specific `[[ ]]` and `source` with POSIX `[ ]` and `.` in
   SDKMAN .bashrc snippets (java/install.sh, kotlin/install.sh,
   full-sandbox/install.sh). Ubuntu's /bin/sh is dash, not bash.

Added:
- experiments/test-bashrc-merge.sh  — reproduces the bug (confirms root cause)
- experiments/test-bashrc-merge-fix.sh — verifies the fix (13/13 tests pass)
- docs/case-studies/issue-66/CASE-STUDY.md — full root cause analysis

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@konard konard changed the title [WIP] We should not run bash inside bash fix: .bashrc merge algorithm corrupted multi-line shell constructs (issue #66) Mar 6, 2026
@konard konard marked this pull request as ready for review March 6, 2026 11:10
@konard
Copy link
Member Author

konard commented Mar 6, 2026

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost estimation:

  • Public pricing estimate: $2.894386
  • Calculated by Anthropic: $3.444445 USD
  • Difference: $0.550059 (+19.00%)
    📎 Log file uploaded as Gist (3464KB)
    🔗 View complete solution draft log

Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard
Copy link
Member Author

konard commented Mar 6, 2026

✅ Ready to merge

This pull request is now ready to be merged:

  • All CI checks have passed
  • No merge conflicts
  • No pending changes

Monitored by hive-mind with --auto-restart-until-mergeable flag

@konard konard merged commit 6dd0cde into main Mar 6, 2026
19 checks passed
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.

We should not run bash inside bash

1 participant