Skip to content

Commit 28bc64c

Browse files
authored
Merge pull request #16 from Thavarshan/refactor/package-manager-abstraction
Release v1.9.0: Critical production fixes for error handling, state management, and security
2 parents 7f7d850 + 3bb3572 commit 28bc64c

8 files changed

Lines changed: 1873 additions & 874 deletions

File tree

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,8 @@ dist
131131

132132
# Mac files
133133
.DS_Store
134+
135+
# notes
136+
notes.md
137+
FEATURE_CHECKLIST.md
138+
IMPLEMENTATION_GUIDE.md

CHANGELOG.md

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,59 @@
22

33
## [Unreleased]
44

5-
### Removed
5+
## [v1.9.0](https://github.com/Thavarshan/phpvm/compare/v1.8.0...v1.9.0) - 2026-01-30
6+
7+
### Fixed
8+
9+
- **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.
10+
- **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.
11+
- **Fixed apt install/uninstall symmetry:** Uninstall now removes `php${version}-cli`, `php${version}-common`, and `php${version}-fpm` packages symmetrically with what install creates.
12+
- **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.
13+
- **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.
14+
- **Fixed path traversal vulnerability in alias resolution:** `phpvm_resolve_version` now validates alias names before file access, preventing path traversal attacks like `../../../etc/passwd`.
15+
- **Fixed path traversal vulnerability in alias commands:** `phpvm_alias` now validates alias names BEFORE any file path operations.
16+
- **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.
17+
- **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.
18+
- **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`.
19+
- **Fixed system PHP symlink consistency:** System switching now calls `update_current_symlink` to maintain consistent `$PHPVM_DIR/current` symlink behavior across all switching modes.
20+
- **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.
21+
- **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.
22+
- **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.
23+
- **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.
24+
- **Fixed `phpvm which` for unversioned formulas:** Correctly returns path to unversioned PHP installed as `php` formula.
25+
- **Fixed apt package search:** `pkg_search_php()` now explicitly checks for `Candidate: (none)` to avoid false positives from `apt-cache policy`.
26+
- **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.
27+
- **Fixed `phpvm_which()` failure propagation:** Now properly propagates failures from `phpvm_current` using `|| return $?`.
28+
- **Fixed shellcheck SC2221/SC2222 warnings:** Simplified `phpvm_is_sourced()` case pattern to avoid overlapping matches.
29+
30+
### Changed
31+
32+
- **Introduced `command_exists()` helper:** Replaced 40+ instances of `command -v X > /dev/null 2>&1` with single reusable function for cleaner command availability checks.
33+
- **Introduced `ensure_phpvm_dirs()` function:** Consolidated repeated `mkdir -p $PHPVM_DIR/X` patterns into centralized directory creation function.
34+
- **Introduced `brew_link_php_unversioned()` function:** Extracted duplicate `brew link php --force --overwrite` logic with error handling into single reusable function.
35+
- **Introduced `is_valid_version_format()` function:** Consolidated duplicate version regex validation pattern into single validation helper.
36+
- **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.
37+
- **Reordered version switching flow:** Now resolves target formula, then unlinks all PHP, then links resolved formula, preventing "version check breaks after unlink" bugs.
38+
- **Improved Linux binary scanning:** Broadened skip patterns to prevent accidentally executing PHP helper binaries (`*fpm*`, `*cgi*`, `*dbg*`, `*ize*`, `*config*`).
39+
- **Ubuntu/Debian apt packages:** Changed from non-existent `php8.2` to actual `php8.2-cli` format used by ondrej/sury PPA.
40+
- **Fedora/RHEL dnf packages:** Implemented correct module stream approach instead of fictional versioned packages.
41+
- **Brew availability check:** Changed from fragile `brew search | grep` to stable `brew info <formula>` API.
42+
- **Trap preservation in `phpvm_with_lock()`:** Now saves and restores user's existing trap handlers instead of clobbering them.
43+
- **Stale lock detection and auto-cleanup:** Lock mechanism now checks if lock holder PID is still running and automatically removes stale locks.
44+
45+
### Added
46+
47+
- **Interactive shell guard:** Auto-switch from `.phpvmrc` now only runs in interactive shells using `case $- in *i*)` pattern.
48+
- **Test mode package manager bypass:** Test mode now sets sandbox defaults without requiring actual brew/apt/dnf.
49+
50+
### Internal
651

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

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

CLAUDE.md

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ The tool detects and works with multiple package managers:
4747
- Handles corrupted/invalid `.phpvmrc` files gracefully
4848

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

5555
## Development Guidelines
5656

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

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

7979
### Adding New Commands
80+
8081
1. Add command handler in the `main()` function case statement
8182
2. Implement the command function following naming convention `command_name()`
8283
3. Add help text in `print_help()`
83-
4. Add tests in the `run_tests()` function
84+
4. Add BATS tests in the `tests/` directory
8485

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

9293
### Testing Changes
94+
9395
```bash
9496
# Run all tests
95-
./phpvm.sh test
97+
bats tests/
98+
99+
# Run specific test file
100+
bats tests/01_core.bats
96101

97102
# Enable debug mode for troubleshooting
98-
DEBUG=true ./phpvm.sh test
103+
DEBUG=true bats tests/
99104

100-
# Test specific functionality manually
101-
DEBUG=true ./phpvm.sh install 8.1
102-
DEBUG=true ./phpvm.sh use 8.1
105+
# Test specific functionality manually with test mode
106+
PHPVM_TEST_MODE=true DEBUG=true ./phpvm.sh install 8.1
107+
PHPVM_TEST_MODE=true DEBUG=true ./phpvm.sh use 8.1
103108

104109
# Check shell syntax
105110
bash -n phpvm.sh
@@ -119,13 +124,13 @@ time ./phpvm.sh help
119124

120125
## Key Functions in phpvm.sh
121126

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

130135
## File Structure
131136

@@ -185,4 +190,4 @@ phpvm/
185190
- Lightweight single-script architecture
186191
- Minimal external dependencies
187192
- Fast execution due to bash implementation
188-
- Efficient directory traversal for `.phpvmrc` detection
193+
- Efficient directory traversal for `.phpvmrc` detection

CONTRIBUTING.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,6 @@ make check
142142

143143
Add tests for new features:
144144

145-
**Built-in tests** - Add to `phpvm.sh` `run_tests()` function:
146-
147-
```bash
148-
test_your_feature() {
149-
# Test logic here
150-
return 0
151-
}
152-
```
153-
154145
**BATS tests** - Add to appropriate file in `tests/`:
155146

156147
```bash
@@ -201,8 +192,6 @@ make release # Prepare for release
201192

202193
```bash
203194
# Run phpvm tests
204-
bash phpvm.sh test
205-
206195
# Run BATS tests
207196
bats tests/
208197

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ If you experience issues with `phpvm`, try the following:
317317

318318
### General Issues
319319

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

0 commit comments

Comments
 (0)