diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index ff4f0a8..11b356c 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -46,7 +46,7 @@ jobs: if: matrix.os == 'linux' run: | sudo apt-get update - sudo apt-get install -y bubblewrap libseccomp-dev gcc socat ripgrep apparmor-profiles + sudo apt-get install -y bubblewrap libseccomp-dev gcc socat ripgrep apparmor-profiles zsh - name: Enable unprivileged user namespaces (Linux) if: matrix.os == 'linux' @@ -63,7 +63,7 @@ jobs: - name: Install system dependencies (macOS) if: matrix.os == 'macos' run: | - brew install ripgrep + brew install ripgrep zsh - name: Install Node dependencies run: npm install diff --git a/test/sandbox/integration.test.ts b/test/sandbox/integration.test.ts index 3594f42..8833cef 100644 --- a/test/sandbox/integration.test.ts +++ b/test/sandbox/integration.test.ts @@ -447,6 +447,86 @@ describe('Sandbox Integration Tests', () => { expect(result.stdout).not.toContain('line1') }) }) + + describe('Shell Selection (binShell parameter)', () => { + it('should execute commands with zsh when binShell is specified', async () => { + if (skipIfNotLinux()) { + return + } + + // Check if zsh is available + const zshCheck = spawnSync('which zsh', { shell: true, encoding: 'utf8' }) + if (zshCheck.status !== 0) { + console.log('zsh not available, skipping test') + return + } + + // Use a zsh-specific feature: $ZSH_VERSION + const command = await SandboxManager.wrapWithSandbox( + 'echo "Shell: $ZSH_VERSION"', + 'zsh' + ) + + const result = spawnSync(command, { + shell: true, + encoding: 'utf8', + timeout: 5000, + }) + + expect(result.status).toBe(0) + // Should contain version number (e.g., "Shell: 5.8.1") + expect(result.stdout).toMatch(/Shell: \d+\.\d+/) + }) + + it('should use zsh syntax successfully with binShell=zsh', async () => { + if (skipIfNotLinux()) { + return + } + + // Check if zsh is available + const zshCheck = spawnSync('which zsh', { shell: true, encoding: 'utf8' }) + if (zshCheck.status !== 0) { + console.log('zsh not available, skipping test') + return + } + + // Use zsh parameter expansion feature + const command = await SandboxManager.wrapWithSandbox( + 'VAR="hello world" && echo ${VAR:u}', + 'zsh' + ) + + const result = spawnSync(command, { + shell: true, + encoding: 'utf8', + timeout: 5000, + }) + + expect(result.status).toBe(0) + expect(result.stdout).toContain('HELLO WORLD') + }) + + it('should default to bash when binShell is not specified', async () => { + if (skipIfNotLinux()) { + return + } + + // Check for bash-specific variable + const command = await SandboxManager.wrapWithSandbox( + 'echo "Shell: $BASH_VERSION"' + ) + + const result = spawnSync(command, { + shell: true, + encoding: 'utf8', + timeout: 5000, + }) + + expect(result.status).toBe(0) + // Should contain bash version + expect(result.stdout).toMatch(/Shell: \d+\.\d+/) + }) + }) }) // ========================================================================== @@ -755,5 +835,64 @@ describe('Sandbox Integration Tests', () => { expect(result.stdout).not.toContain('line1') }) }) + + describe('Shell Selection (binShell parameter)', () => { + it('should execute commands with zsh when binShell is specified', async () => { + if (skipIfNotLinux()) { + return + } + + // Check if zsh is available + const zshCheck = spawnSync('which zsh', { shell: true, encoding: 'utf8' }) + if (zshCheck.status !== 0) { + console.log('zsh not available, skipping test') + return + } + + // Use a zsh-specific feature: $ZSH_VERSION + const command = await SandboxManager.wrapWithSandbox( + 'echo "Shell: $ZSH_VERSION"', + 'zsh' + ) + + const result = spawnSync(command, { + shell: true, + encoding: 'utf8', + timeout: 5000, + }) + + expect(result.status).toBe(0) + // Should contain version number (e.g., "Shell: 5.8.1") + expect(result.stdout).toMatch(/Shell: \d+\.\d+/) + }) + + it('should use zsh syntax successfully with binShell=zsh', async () => { + if (skipIfNotLinux()) { + return + } + + // Check if zsh is available + const zshCheck = spawnSync('which zsh', { shell: true, encoding: 'utf8' }) + if (zshCheck.status !== 0) { + console.log('zsh not available, skipping test') + return + } + + // Use zsh parameter expansion feature + const command = await SandboxManager.wrapWithSandbox( + 'VAR="hello world" && echo ${VAR:u}', + 'zsh' + ) + + const result = spawnSync(command, { + shell: true, + encoding: 'utf8', + timeout: 5000, + }) + + expect(result.status).toBe(0) + expect(result.stdout).toContain('HELLO WORLD') + }) + }) }) })