Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,8 @@ dist

# Mac files
.DS_Store

# notes
notes.md
FEATURE_CHECKLIST.md
IMPLEMENTATION_GUIDE.md
54 changes: 52 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,59 @@

## [Unreleased]

### Removed
## [v1.9.0](https://github.com/Thavarshan/phpvm/compare/v1.8.0...v1.9.0) - 2026-01-30

### Fixed

- **Fixed error propagation in version resolution:** Commands like `phpvm use latest` and `phpvm install latest` now correctly propagate failures from `phpvm_resolve_version` instead of silently swallowing errors.
- **Fixed state consistency in `switch_to_system_php`:** State file (`active_version=system`) is now only written AFTER the switch operation succeeds, preventing state lies when brew link operations fail.
- **Fixed apt install/uninstall symmetry:** Uninstall now removes `php${version}-cli`, `php${version}-common`, and `php${version}-fpm` packages symmetrically with what install creates.
- **Fixed alias directory reliability:** Alias directory creation is now required (not best-effort). If `$PHPVM_DIR/alias` cannot be created, phpvm fails with a clear error message.
- **Fixed symlink robustness:** `update_current_symlink` now uses `command -v php` to resolve the actual binary path, ensuring the symlink points to what the shell would execute.
- **Fixed path traversal vulnerability in alias resolution:** `phpvm_resolve_version` now validates alias names before file access, preventing path traversal attacks like `../../../etc/passwd`.
- **Fixed path traversal vulnerability in alias commands:** `phpvm_alias` now validates alias names BEFORE any file path operations.
- **Fixed trap restoration in sourced shells:** `phpvm_with_lock` now explicitly clears traps with `trap - SIGNAL` when user had no existing trap, preventing phpvm's cleanup traps from being permanently installed in the user's shell session.
- **Fixed init ordering for help/version commands:** Moved command parsing before `phpvm_init_or_die` so `phpvm help` and `phpvm version` work without requiring package manager detection or system initialization.
- **Fixed Linux version listing accuracy:** Unified all Linux package managers (apt/dnf/yum/pacman) to use `phpvm_linux_installed_versions` which scans actual binaries, eliminating inaccurate package name listings like `8.2-cli` or `8.2-fpm`.
- **Fixed system PHP symlink consistency:** System switching now calls `update_current_symlink` to maintain consistent `$PHPVM_DIR/current` symlink behavior across all switching modes.
- **Fixed alias security vulnerability:** Reordered validation in `phpvm_alias` to validate version format before using it in file path checks, preventing potential path traversal attacks with malicious alias targets.
- **Fixed yum installation strategy:** Implemented proper Remi repository detection and naming conventions (`php82-php-cli` format), replacing incorrect `yum install php8.2` approach that would always fail.
- **Fixed lock PID staleness:** Added explicit `lock_pid=""` reset at top of each `phpvm_lock` loop iteration to prevent stale PID values in error messages.
- **Fixed unversioned PHP formula detection:** Homebrew's unversioned `php` formula is now correctly identified before any unlinking operations, preventing false version matches from system PHP.
- **Fixed `phpvm which` for unversioned formulas:** Correctly returns path to unversioned PHP installed as `php` formula.
- **Fixed apt package search:** `pkg_search_php()` now explicitly checks for `Candidate: (none)` to avoid false positives from `apt-cache policy`.
- **Fixed `echo` usage in input validation:** Replaced `echo "$var" | grep` with `printf '%s\n' "$var" | grep` throughout to prevent interpretation of strings like `-n`, `-e`, backslash escapes.
- **Fixed `phpvm_which()` failure propagation:** Now properly propagates failures from `phpvm_current` using `|| return $?`.
- **Fixed shellcheck SC2221/SC2222 warnings:** Simplified `phpvm_is_sourced()` case pattern to avoid overlapping matches.

### Changed

- **Introduced `command_exists()` helper:** Replaced 40+ instances of `command -v X > /dev/null 2>&1` with single reusable function for cleaner command availability checks.
- **Introduced `ensure_phpvm_dirs()` function:** Consolidated repeated `mkdir -p $PHPVM_DIR/X` patterns into centralized directory creation function.
- **Introduced `brew_link_php_unversioned()` function:** Extracted duplicate `brew link php --force --overwrite` logic with error handling into single reusable function.
- **Introduced `is_valid_version_format()` function:** Consolidated duplicate version regex validation pattern into single validation helper.
- **Added `brew_php_major_minor()` helper:** Reads version directly from `$HOMEBREW_PREFIX/opt/php/bin/php` instead of PATH-based `php -r`, eliminating conflicts with system PHP.
- **Reordered version switching flow:** Now resolves target formula, then unlinks all PHP, then links resolved formula, preventing "version check breaks after unlink" bugs.
- **Improved Linux binary scanning:** Broadened skip patterns to prevent accidentally executing PHP helper binaries (`*fpm*`, `*cgi*`, `*dbg*`, `*ize*`, `*config*`).
- **Ubuntu/Debian apt packages:** Changed from non-existent `php8.2` to actual `php8.2-cli` format used by ondrej/sury PPA.
- **Fedora/RHEL dnf packages:** Implemented correct module stream approach instead of fictional versioned packages.
- **Brew availability check:** Changed from fragile `brew search | grep` to stable `brew info <formula>` API.
- **Trap preservation in `phpvm_with_lock()`:** Now saves and restores user's existing trap handlers instead of clobbering them.
- **Stale lock detection and auto-cleanup:** Lock mechanism now checks if lock holder PID is still running and automatically removes stale locks.

### Added

- **Interactive shell guard:** Auto-switch from `.phpvmrc` now only runs in interactive shells using `case $- in *i*)` pattern.
- **Test mode package manager bypass:** Test mode now sets sandbox defaults without requiring actual brew/apt/dnf.

### Internal

- **Redundant qa.sh script:** Removed `qa.sh` as its functionality is fully covered by `make check`.
- **Bash-only support documented:** Added explicit notice that script requires bash (uses bashisms).
- **Intentional symlink behavior clarified:** Added comment explaining `update_current_symlink()` links to resolved `php` binary by design.
- **Dnf module stream workflow:** Added inline documentation about RHEL/Fedora module stream management.
- **Version bump:** Updated to v1.9.0.
- **All tests passing:** 51 BATS tests pass (added 4 security tests for path traversal protection).
- **Release documentation:** Added RELEASE_CHECKLIST.md and RELEASE_SUMMARY.md.

## [v1.8.0](https://github.com/Thavarshan/phpvm/compare/v1.7.0...v1.8.0) - 2026-01-12

Expand Down
43 changes: 24 additions & 19 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ The tool detects and works with multiple package managers:
- Handles corrupted/invalid `.phpvmrc` files gracefully

### Testing Framework
- Built-in self-tests (`phpvm test`)
- Mock environment creation for testing
- BATS (Bash Automated Testing System) test suite in `tests/` directory
- Mock environment creation for testing with `PHPVM_TEST_MODE=true`
- Comprehensive test coverage including edge cases
- No external testing dependencies required
- Run tests with: `bats tests/`

## Development Guidelines

Expand All @@ -61,8 +61,8 @@ The tool detects and works with multiple package managers:
- Helper functions to reduce code duplication

### Testing
- Run tests: `./phpvm.sh test`
- Tests create isolated mock environments
- Run tests: `bats tests/`
- Tests create isolated mock environments with `PHPVM_TEST_MODE=true`
- All core functionality is tested including error conditions
- Tests verify cross-platform compatibility
- GitHub Actions runs automated tests on Ubuntu and macOS
Expand All @@ -77,10 +77,11 @@ The tool detects and works with multiple package managers:
## Common Development Tasks

### Adding New Commands

1. Add command handler in the `main()` function case statement
2. Implement the command function following naming convention `command_name()`
3. Add help text in `print_help()`
4. Add tests in the `run_tests()` function
4. Add BATS tests in the `tests/` directory

### Supporting New Package Managers
1. Add detection logic in `detect_system()`
Expand All @@ -90,16 +91,20 @@ The tool detects and works with multiple package managers:
5. Add uninstall logic in `uninstall_php()`

### Testing Changes

```bash
# Run all tests
./phpvm.sh test
bats tests/

# Run specific test file
bats tests/01_core.bats

# Enable debug mode for troubleshooting
DEBUG=true ./phpvm.sh test
DEBUG=true bats tests/

# Test specific functionality manually
DEBUG=true ./phpvm.sh install 8.1
DEBUG=true ./phpvm.sh use 8.1
# Test specific functionality manually with test mode
PHPVM_TEST_MODE=true DEBUG=true ./phpvm.sh install 8.1
PHPVM_TEST_MODE=true DEBUG=true ./phpvm.sh use 8.1

# Check shell syntax
bash -n phpvm.sh
Expand All @@ -119,13 +124,13 @@ time ./phpvm.sh help

## Key Functions in phpvm.sh

- `main()` - Entry point with command routing (phpvm.sh:960+)
- `detect_system()` - Package manager and OS detection (phpvm.sh:65)
- `install_php()` - PHP version installation logic (phpvm.sh:115+)
- `use_php_version()` - Version switching functionality (phpvm.sh:186+)
- `find_phpvmrc()` - Auto-detection of .phpvmrc files (phpvm.sh:270+)
- `run_tests()` - Built-in test framework (phpvm.sh:470+)
- Helper functions: `run_with_sudo()`, `log_with_timestamp()`, output functions
- `main()` - Entry point with command routing
- `detect_system()` - Package manager and OS detection
- `install_php()` - PHP version installation logic
- `use_php_version()` - Version switching functionality
- `find_phpvmrc()` - Auto-detection of .phpvmrc files
- Helper functions: `run_with_sudo()`, `phpvm_echo()`, `phpvm_err()`, `phpvm_warn()`, `phpvm_debug()`
- Package manager abstraction: `pkg_install_php()`, `pkg_uninstall_php()`, `pkg_search_php()`

## File Structure

Expand Down Expand Up @@ -185,4 +190,4 @@ phpvm/
- Lightweight single-script architecture
- Minimal external dependencies
- Fast execution due to bash implementation
- Efficient directory traversal for `.phpvmrc` detection
- Efficient directory traversal for `.phpvmrc` detection
11 changes: 0 additions & 11 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,6 @@ make check

Add tests for new features:

**Built-in tests** - Add to `phpvm.sh` `run_tests()` function:

```bash
test_your_feature() {
# Test logic here
return 0
}
```

**BATS tests** - Add to appropriate file in `tests/`:

```bash
Expand Down Expand Up @@ -201,8 +192,6 @@ make release # Prepare for release

```bash
# Run phpvm tests
bash phpvm.sh test

# Run BATS tests
bats tests/

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ If you experience issues with `phpvm`, try the following:

### General Issues

- Run `phpvm test` to verify all functions are working correctly
- Run the test suite with `bats tests/` to verify all functions are working correctly
- Check the phpvm version with `phpvm version` or `phpvm --version`
- Ensure your shell profile is sourcing `phpvm.sh`
- Restart your terminal after installing or updating
Expand Down
Loading
Loading