Skip to content

Commit f2b40b7

Browse files
authored
Merge pull request #11 from mojwang/feat/signal-safe-cleanup
feat: implement signal-safe cleanup and temp file handling
2 parents 3f443cb + af6a105 commit f2b40b7

19 files changed

Lines changed: 1955 additions & 620 deletions

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ logs/
4040
tmp/
4141
temp/
4242
.tmp/
43+
tests/tmp.*
44+
tests/failing_test.*
45+
tests/interrupt_test.*
46+
tests/timeout_cleanup.*
47+
tests/trap_test.*
48+
tests/syntax_test.*
49+
tests/test_syntax_error.sh
4350

4451
# Backup files
4552
*.backup

CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
### Features
1717

1818
* Add support for community MCP servers ([47cc153](https://github.com/mojwang/macbook-dev-setup/commit/47cc153a6927d7d537d1f71093427062d32ae9e1))
19-
2019
# [2.6.0](https://github.com/mojwang/macbook-dev-setup/compare/v2.5.0...v2.6.0) (2025-07-26)
2120

2221

CLAUDE.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ MCP servers installed:
118118
- **memory**: In-memory key-value storage for temporary data
119119
- **git**: Tools to read, search, and manipulate Git repositories
120120
- **fetch**: Web content fetching and conversion for efficient LLM usage
121+
- **sequentialthinking**: Dynamic problem-solving through iterative thought processes
122+
- **context7**: Documentation retrieval for any library (community server)
123+
- **playwright**: Browser automation and testing (community server)
124+
- **figma**: Figma design context integration (community server)
125+
- **semgrep**: Code analysis and pattern matching (community server)
126+
- **exa**: Enhanced search capabilities (community server)
121127

122128
### Git Commit Helpers
123129
```bash
@@ -152,14 +158,27 @@ The `--sync` flag detects and installs new packages added to configuration files
152158

153159
### Script Organization
154160
- **Main Scripts**: `setup.sh` (production) and `setup-validate.sh` (validation/dry-run)
161+
- **Core Libraries** in `/lib/`:
162+
- `common.sh`: Shared functions and utilities
163+
- `signal-safety.sh`: Signal handling and cleanup framework
164+
- `backup-manager.sh`: Centralized backup management
165+
- `config.sh`: Configuration management
155166
- **Component Scripts** in `/scripts/`:
156167
- `install-homebrew.sh`: Installs Homebrew package manager
157168
- `install-packages.sh`: Installs packages from Brewfile
158169
- `setup-dotfiles.sh`: Deploys dotfiles with automatic backups
159170
- `setup-applications.sh`: Installs macOS desktop applications
160171
- `setup-macos.sh`: Configures macOS system preferences
161172
- `setup-git-hooks.sh`: Configures conventional commit hooks
173+
- `setup-claude-mcp.sh`: Installs and configures MCP servers
174+
- `setup-terminal-fonts.sh`: Configures terminal fonts
175+
- `setup-warp.sh`: Warp terminal specific optimizations
162176
- `commit-helper.sh`: Interactive conventional commit creator
177+
- `cleanup-artifacts.sh`: Periodic maintenance and cleanup
178+
- `health-check.sh`: System health verification
179+
- `update.sh`: Update all tools and dependencies
180+
- `uninstall.sh`: Clean removal with backups
181+
- `rollback.sh`: Restore from previous backups
163182

164183
### Key Configuration Files
165184
- `homebrew/Brewfile`: Package definitions (formulae, casks, VS Code extensions)
@@ -195,6 +214,107 @@ The `--sync` flag detects and installs new packages added to configuration files
195214
- Timeout protection (30s) for potentially hanging commands
196215
- Git is configured with security-conscious settings (fsckObjects enabled)
197216

217+
## Security and Signal Safety
218+
219+
### Signal-Safe Cleanup Requirements
220+
All scripts that perform system modifications MUST implement signal-safe cleanup:
221+
222+
1. **Source the signal-safety library** at the beginning of the script:
223+
```bash
224+
source "$ROOT_DIR/lib/signal-safety.sh"
225+
```
226+
227+
2. **Implement a cleanup function** specific to your script's needs:
228+
```bash
229+
cleanup_yourscript() {
230+
# Clean up temporary files
231+
rm -f "${TEMP_FILE:-}" 2>/dev/null || true
232+
233+
# Kill any background processes
234+
[[ -n "${CHILD_PID:-}" ]] && kill "$CHILD_PID" 2>/dev/null || true
235+
236+
# Remove partial installations
237+
[[ -d "${WORK_DIR:-}" ]] && rm -rf "$WORK_DIR" 2>/dev/null || true
238+
239+
# Call default cleanup
240+
default_cleanup
241+
}
242+
```
243+
244+
3. **Register the cleanup function** immediately after defining it:
245+
```bash
246+
setup_cleanup "cleanup_yourscript"
247+
```
248+
249+
### Critical Cleanup Areas
250+
When implementing cleanup, ensure these artifacts are handled:
251+
252+
- **Package Managers**: npm node_modules, Python venvs, Ruby gems
253+
- **Build Artifacts**: Compiled binaries, object files, cache directories
254+
- **Temporary Files**: Config backups, download files, lock files
255+
- **Background Processes**: Any spawned child processes or daemons
256+
- **Partial Installations**: Incomplete setups that could cause issues
257+
258+
### Security Best Practices
259+
260+
1. **Never leave sensitive data** in temporary files or logs
261+
2. **Use secure temp directories**: `mktemp -d` with proper permissions
262+
3. **Validate all inputs** before using in commands
263+
4. **Avoid eval** unless absolutely necessary
264+
5. **Quote all variables** to prevent injection: `"$var"` not `$var`
265+
6. **Set restrictive permissions** on created files: `umask 077`
266+
7. **Clean up secrets** from memory/disk after use
267+
268+
### Testing Signal Safety
269+
Always test your cleanup implementation:
270+
271+
```bash
272+
# Start your script and interrupt it
273+
./your-script.sh &
274+
PID=$!
275+
sleep 2
276+
kill -INT $PID
277+
# Verify no artifacts remain
278+
```
279+
280+
## Testing Framework
281+
282+
### Running Tests
283+
```bash
284+
# Run all tests
285+
./tests/run_tests.sh
286+
287+
# Run specific test suites
288+
./tests/run_tests.sh unit # Unit tests only
289+
./tests/run_tests.sh integration # Integration tests only
290+
./tests/run_tests.sh ci # CI-specific tests
291+
292+
# Run tests in parallel (faster)
293+
./tests/run_tests_parallel.sh
294+
295+
# Run with custom parallelism
296+
TEST_JOBS=8 ./tests/run_tests.sh
297+
```
298+
299+
### Test Organization
300+
- **Unit Tests** (`tests/unit/`): Test individual functions and components
301+
- **Integration Tests** (`tests/integration/`): Test script interactions
302+
- **CI Tests** (`tests/ci/`): Tests specific to CI environment
303+
- **Stress Tests** (`tests/stress/`): Performance and load testing
304+
- **Performance Tests** (`tests/performance/`): Benchmark and optimization tests
305+
306+
### Writing Tests
307+
Use the test framework's built-in functions:
308+
```bash
309+
it "should describe what it tests"
310+
assert_equals "expected" "actual" "Test description"
311+
assert_true "[[ condition ]]" "Condition should be true"
312+
assert_false "[[ condition ]]" "Condition should be false"
313+
assert_contains "haystack" "needle" "Should contain substring"
314+
assert_file_exists "/path/to/file" "File should exist"
315+
assert_dir_exists "/path/to/dir" "Directory should exist"
316+
```
317+
198318
## Setup Script Maintenance
199319

200320
When adding new functionality or capabilities to this project, always check if the setup script needs updating:
@@ -207,3 +327,33 @@ When adding new functionality or capabilities to this project, always check if t
207327
6. **Update documentation**: Document new features in this file if needed
208328

209329
After any changes, run the setup script to ensure everything works correctly.
330+
331+
## Important Behavioral Guidelines
332+
333+
- Do only what has been asked; nothing more, nothing less
334+
- Never create files unless absolutely necessary for the task
335+
- Always prefer editing existing files over creating new ones
336+
- Never proactively create documentation files (*.md) or README files unless explicitly requested
337+
- Never commit changes unless explicitly asked to
338+
- When blocked, ask for clarification rather than making assumptions
339+
340+
## Repository Standards
341+
342+
### Version Management
343+
- Current version is tracked in `VERSION` file
344+
- Semantic versioning is enforced via CI/CD
345+
- Changelog follows Keep a Changelog format
346+
- Automatic releases via semantic-release
347+
348+
### CI/CD Pipeline
349+
- GitHub Actions for automated testing
350+
- Semantic release for version management
351+
- Branch protection on main branch
352+
- All PRs require passing tests
353+
- Claude Code Review integration for AI-assisted reviews
354+
355+
### Code Quality
356+
- ShellCheck for shell script linting
357+
- Consistent error handling patterns
358+
- Comprehensive test coverage
359+
- Security scanning in CI pipeline

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.8.0
1+
2.8.0

config/global-claude.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ This file provides baseline guidance to Claude Code across all projects. Project
2424
- Provide dry-run/preview modes for all destructive operations
2525
- Detailed error handling with recovery options
2626
- Optional logging for troubleshooting
27+
- Signal-safe cleanup handlers for all system-modifying scripts
28+
- Atomic file operations to prevent partial writes
2729

2830
## File Organization
2931

@@ -70,6 +72,16 @@ This file provides baseline guidance to Claude Code across all projects. Project
7072
- Follow conventional commit message formats when they exist in the project
7173
- Keep commits focused and atomic - one logical change per commit
7274

75+
## Security Practices
76+
77+
- Always quote variables in shell scripts: `"$var"` not `$var`
78+
- Validate and sanitize all user inputs
79+
- Use `mktemp` for temporary files with restrictive permissions
80+
- Never store secrets in code or logs
81+
- Clean up sensitive data from memory/disk after use
82+
- Implement proper signal handling for cleanup on interruption
83+
- Use secure defaults and fail closed, not open
84+
7385
## Important Behavioral Guidelines
7486

7587
- Do only what has been asked; nothing more, nothing less

docs/SIGNAL_SAFETY.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Signal Safety and Cleanup Guide
2+
3+
This document explains how scripts in this repository handle signals and cleanup to ensure no temporary files or resources are left behind, even when interrupted.
4+
5+
## The Problem
6+
7+
When a script is interrupted (e.g., via Ctrl+C), it receives a SIGINT signal. If the script only uses `trap cleanup EXIT`, the cleanup function won't run because:
8+
- `EXIT` trap only triggers on normal script termination
9+
- SIGINT causes immediate termination unless explicitly handled
10+
- This can leave temporary files, directories, and other resources behind
11+
12+
## The Solution
13+
14+
All scripts that create temporary resources should use signal-aware traps:
15+
16+
```bash
17+
# ❌ BAD: Only handles normal exit
18+
trap cleanup EXIT
19+
20+
# ✅ GOOD: Handles interrupts and other signals
21+
trap cleanup EXIT INT TERM HUP
22+
```
23+
24+
### Signal Explanation
25+
26+
- **EXIT**: Normal script termination
27+
- **INT**: Interrupt signal (Ctrl+C)
28+
- **TERM**: Termination request (kill command)
29+
- **HUP**: Terminal hangup (closing terminal)
30+
31+
## Implementation Guide
32+
33+
### Basic Pattern
34+
35+
```bash
36+
#!/bin/bash
37+
38+
# Define cleanup function
39+
cleanup() {
40+
rm -f "$temp_file"
41+
rm -rf "$temp_dir"
42+
}
43+
44+
# Set up signal-safe trap
45+
trap cleanup EXIT INT TERM HUP
46+
47+
# Create temporary resources
48+
temp_file=$(mktemp /tmp/myapp.XXXXXX)
49+
temp_dir=$(mktemp -d /tmp/myapp_dir.XXXXXX)
50+
51+
# Your script logic here
52+
```
53+
54+
### Using the Signal Safety Library
55+
56+
For more complex scripts, use the provided library:
57+
58+
```bash
59+
#!/bin/bash
60+
61+
source "$(dirname "$0")/../lib/signal-safety.sh"
62+
63+
# Define custom cleanup
64+
cleanup() {
65+
echo "Cleaning up..."
66+
# Your cleanup code here
67+
default_cleanup # Cleans registered temp resources
68+
}
69+
70+
# Setup signal handling
71+
setup_cleanup "cleanup"
72+
73+
# Use safe temp file creation
74+
temp_file=$(safe_mktemp "myapp.XXXXXX")
75+
temp_dir=$(safe_mktemp_dir "myapp_work.XXXXXX")
76+
```
77+
78+
### Preventing Multiple Cleanup Calls
79+
80+
The signal-safety library ensures cleanup only runs once:
81+
82+
```bash
83+
CLEANUP_DONE=false
84+
85+
safe_cleanup() {
86+
if [[ "$CLEANUP_DONE" == "false" ]]; then
87+
CLEANUP_DONE=true
88+
cleanup
89+
fi
90+
}
91+
92+
trap safe_cleanup EXIT INT TERM HUP
93+
```
94+
95+
## Testing Signal Handling
96+
97+
Run the signal handling tests:
98+
99+
```bash
100+
./tests/test_signal_handling.sh
101+
```
102+
103+
This test suite verifies:
104+
- Cleanup on SIGINT (Ctrl+C)
105+
- Cleanup on SIGTERM
106+
- Proper trap inheritance in subshells
107+
- Prevention of multiple cleanup calls
108+
109+
## CI/CD Considerations
110+
111+
GitHub Actions and other CI systems may forcefully terminate jobs. Our scripts handle this by:
112+
113+
1. Using proper signal traps in all scripts
114+
2. Running periodic cleanup tests in CI
115+
3. Providing a cleanup utility for safety
116+
117+
## Cleanup Utility
118+
119+
For additional safety, a cleanup utility is provided:
120+
121+
```bash
122+
# Dry run (default) - shows what would be cleaned
123+
./scripts/cleanup-artifacts.sh
124+
125+
# Actually clean up
126+
./scripts/cleanup-artifacts.sh --execute
127+
128+
# Add to crontab for automatic cleanup
129+
0 3 * * 0 /path/to/cleanup-artifacts.sh --execute
130+
```
131+
132+
## Best Practices
133+
134+
1. **Always use signal-aware traps** when creating temporary resources
135+
2. **Use /tmp for temporary files** via `mktemp /tmp/prefix.XXXXXX`
136+
3. **Test signal handling** when modifying scripts that create resources
137+
4. **Clean up in reverse order** of resource creation
138+
5. **Use the signal-safety library** for complex scripts
139+
140+
## Verification
141+
142+
To verify no artifacts are left behind:
143+
144+
```bash
145+
# Run CI cleanup verification
146+
./tests/test_ci_cleanup.sh
147+
148+
# Check for common artifacts
149+
find /tmp -name "test_*" -o -name "tmp.*" | wc -l
150+
find ~ -maxdepth 1 -name ".test-setup-backups-*" | wc -l
151+
```
152+
153+
## Updated Scripts
154+
155+
The following scripts have been updated with proper signal handling:
156+
- `lib/common.sh` - Main library with signal-safe trap
157+
- `tests/test_backup_system.sh` - Handles test backup cleanup
158+
- `scripts/rollback.sh` - Cleans up temporary requirements file
159+
- `tests/test_error_recovery.sh` - Cleans up test artifacts
160+
- All scripts using the common library inherit signal safety

0 commit comments

Comments
 (0)