The validatePromptFilePath function used CJS require("path") inline,
violating the project's ESM-only rule. This could trigger Bun
compatibility issues since the project is "type": "module".
Replace with a top-level `import { resolve } from "path"` statement.
Agent: code-health
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
spawn delete was broken for all clouds because execDeleteServer passed
inline scripts (without shebangs) through runBash, which calls
validateScriptContent requiring a #! prefix. Extract spawnBash helper
and add runBashTrusted for locally-generated delete scripts that already
validate their inputs via validateServerIdentifier/validateMetadataValue.
Also fix instanceof Error usage in manifest.ts and history.ts to use
duck typing, matching the convention documented in index.ts and
commands.ts. Fix stale comment in security.ts that claimed colons were
in the server ID allowlist when the regex excludes them.
Agent: code-health
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
validateConnectionIP rejected "localhost" (written by local cloud) and
hostnames like "ssh.app.daytona.io" (written by Daytona), causing
mergeLastConnection to silently discard connection data. This broke
spawn list and spawn delete for these providers.
- Add "localhost" to CONNECTION_SENTINELS
- Add HOSTNAME_PATTERN for valid multi-label DNS hostnames
- Update tests: localhost now valid, add hostname acceptance/rejection tests
Agent: code-health
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: replace hardcoded ~/.spawn/history.json path in security.ts error messages
Error messages in security validation functions (validateConnectionIP,
validateUsername, validateServerIdentifier, validateMetadataValue) hardcoded
~/.spawn/history.json as the fix path. This is wrong when SPAWN_HOME is set,
directing users to a nonexistent file. Replace all 9 occurrences with
'spawn list --clear' which works regardless of SPAWN_HOME and is simpler
than manually editing JSON.
Agent: ux-engineer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: bump cli version to 0.5.17
Required by CLAUDE.md: any change to cli/ needs a version bump.
PR #1520 changes security.ts error messages (cli/ change).
Agent: pr-maintainer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
The buildDeleteScript function in commands.ts interpolated connection.metadata.zone
and connection.metadata.project directly into a bash script string without validation.
A tampered history file could inject arbitrary shell commands via these fields
(e.g., zone='"; rm -rf /; echo "' would escape the double quotes).
Add validateMetadataValue() to security.ts and call it before interpolating
GCP zone and project values into the delete script.
Agent: security-auditor
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* security: fix incomplete command injection detection in prompt validation
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: refine command injection patterns to avoid false positives
Addresses changes requested in PR review:
- Updated && and || patterns to only match when followed by common shell commands
- Added context-aware check to exclude programming expressions like "a > b && c < d"
- Maintains security by still catching shell command chaining attempts
- All security tests pass including new edge case tests
Fixes false positive rejection of legitimate programming expressions
while still detecting shell injection attempts from issue #1400.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Add input validation for SSH connection parameters (IP, username, server_name)
and server identifiers used in delete operations. This prevents command injection
attacks if ~/.spawn/history.json is corrupted or tampered with.
Changes:
- Add validateConnectionIP() - validates IPv4/IPv6 addresses and sentinels
- Add validateUsername() - validates Unix username format
- Add validateServerIdentifier() - validates server names/IDs
- Update cmdConnect() to validate all connection params before use
- Update buildDeleteScript() to validate server IDs before interpolation
- Update mergeLastConnection() to validate data from bash scripts
- Add comprehensive test coverage for all validation functions
- Bump CLI version to 0.3.3 (security patch)
Security impact:
- Prevents HIGH severity command injection via history.ip/user (issue #1381)
- Prevents MEDIUM severity command injection via server_id (issue #1380)
Agent: security-auditor
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhance error messages throughout the codebase to provide clearer
explanations and more actionable guidance for users.
Changes:
Shell Scripts (shared/common.sh):
- Improve non-interactive mode error with better examples
- Expand model ID validation to show valid characters and examples
- Add detailed server name requirements with examples
- Fix diagnostic function to handle cases without fixes section
TypeScript CLI (cli/src/security.ts):
- Enhance identifier validation with bullet points and examples
- Add context about entity type (agent vs cloud) in errors
- Improve path traversal error with specific character explanations
- Better prompt validation messages with plain language guidance
- Improve overly-long identifier/prompt errors with helpful context
TypeScript CLI (cli/src/commands.ts):
- Rewrite download failure messages to be more user-friendly
- Change "Common causes" to "What's wrong" for clarity
- Change "How to fix" to "What to do" for better action orientation
- Add more specific troubleshooting steps for network issues
- Improve wording to be less technical and more helpful
Impact:
- Users get clearer, more actionable error messages
- Error messages now include examples of correct usage
- Reduced cognitive load by using plain language instead of jargon
- Better guidance for fixing issues without needing to consult docs
Agent: ux-engineer
Co-authored-by: Spawn Refactor Service <refactor@spawn.service>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhance error messages across validation and download failures to be more
actionable and user-friendly:
Security validation improvements (cli/src/security.ts):
- validateIdentifier: Add examples of valid names, clearer length error
- validateScriptContent: Improve empty script and shebang error messages
- validatePrompt: Better guidance on prompt requirements and length limits
- validatePromptFilePath: Clearer security warnings with concrete examples
- validatePromptFileStats: More helpful messages for file size/empty errors
Download failure improvements (cli/src/commands.ts):
- reportDownloadFailure: Add "Common causes" section, better 404 guidance
- reportDownloadError: Context-aware messages for timeout vs connection errors
- validateNonEmptyString: Minor wording improvement
All error messages now follow a consistent pattern:
1. What went wrong (clear, specific)
2. Why it might have happened (common causes)
3. How to fix it (numbered, actionable steps)
Agent: ux-engineer
Co-authored-by: Spawn Refactor Service <refactor@spawn.service>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* ux: improve security and validation error messages
Make error messages more user-friendly and actionable:
**Security validation errors:**
- Changed "contains invalid characters" to "Invalid agent: ..." with clearer formatting
- Added context-specific guidance (spawn agents vs spawn clouds)
- Replaced technical jargon with plain language
- Changed "path traversal characters" to list specific disallowed characters
**Prompt validation errors:**
- Replaced "Prompt blocked: contains potentially dangerous pattern" with
"Your prompt contains shell syntax that can't be safely processed"
- Added specific suggestions for each pattern (e.g., 'Instead of "Fix $(ls)",
try "Fix the output of ls command"')
- Included helpful tip about using plain English instead of shell syntax
**Script download errors:**
- Replaced technical "must start with a valid shebang" message with bullet-point
explanation of what went wrong
- Added step-by-step "How to fix" section
- More user-friendly language throughout
**Prompt file errors:**
- Changed "Refusing to read" to "Cannot use... as a prompt file"
- Added clear "How to fix" with example commands
- Better explanation of why certain paths are blocked
All error messages now:
- Start with what went wrong in plain language
- Explain why it happened
- Provide specific next steps to fix it
- Use consistent formatting with bullet points and sections
Agent: ux-engineer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: Replace !! with ;; in gcore case branches in record.sh
Addresses security review feedback. The !! syntax is invalid bash and broke
the test recording infrastructure.
-- refactor/pr-maintainer
---------
Co-authored-by: Spawn Refactor Service <refactor@spawn.service>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Add path validation to --prompt-file to block reading sensitive files
(SSH keys, cloud credentials, .env files, etc.) whose contents would be
sent to remote agents. Also adds file size validation (1MB limit) and
stat-based file type checking.
Fixes#991
Agent: security-auditor
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- validatePrompt max-length error now suggests --prompt-file alternative
- validateScriptContent shebang error explains likely download issue
- Compact list view now shows color legend (green=all, yellow=partial)
- Exit code 1 gets specific guidance (credentials, API, provisioning)
- cmdUpdate network error shows current version for context
- Bump CLI version to 0.2.37
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add log_step() function (cyan) for status/progress messages
- Convert misused log_warn calls to log_step in shared/common.sh
(14 instances: SSH key gen, agent verification, waiting, configuring)
- Convert representative cloud scripts: hetzner, digitalocean, sprite
- Fix misleading validatePrompt error that suggested --prompt-file as a
workaround when it has the same validation
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The spawn scripts themselves use curl|bash to install agents (e.g.
Claude Code). The validateScriptContent check was blocking our own
legitimate scripts. Removed curl|bash and wget|bash from the
dangerous patterns list since the scripts are already fetched from
our trusted GitHub repo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enhance the spawn CLI user experience with actionable error messages,
comprehensive help documentation, and visual progress feedback.
Changes:
- Help text: Add AUTHENTICATION, TROUBLESHOOTING, and MORE INFO sections
- Error messages: Show examples of valid options when validation fails
- Progress indicators: Add spinners for script downloads
- Install flow: Provide clear alternatives when npm install requires sudo
- README: Add environment variable documentation and alternative install URL
- Security errors: Suggest workarounds for false positives
All error messages now follow the pattern:
1. What went wrong
2. Why it matters
3. What to do next
Documentation: .docs/UX_IMPROVEMENTS_20260208.md
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* refactor: extract shared test helpers and utilities
Created centralized test-helpers.ts module to eliminate duplication across test files:
**Extracted Helpers:**
- createMockManifest() - Reusable mock manifest data
- createEmptyManifest() - Empty manifest for edge cases
- createConsoleMocks() - Console spy setup
- createProcessExitMock() - Process exit mock
- restoreMocks() - Mock cleanup utility
- mockSuccessfulFetch() - Simplified successful fetch mock
- mockFailedFetch() - Simplified failed fetch mock
- mockFetchWithStatus() - Fetch mock with custom status
- setupTestEnvironment() - Test directory and env setup
- teardownTestEnvironment() - Cleanup utility
**Deduplication Impact:**
- commands.test.ts: Removed 50+ lines of duplicate mock setup
- manifest.test.ts: Removed 80+ lines of duplicate manifest data and setup code
- integration.test.ts: Removed 40+ lines of duplicate setup/teardown
**Benefits:**
- Single source of truth for test fixtures
- Consistent mock patterns across all tests
- Easier maintenance - changes to test setup in one place
- Improved test readability
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* refactor: Add non-interactive mode for agent execution
Implements --prompt and --prompt-file flags to enable non-interactive
agent execution. This allows users to:
- Execute agents with a prompt and exit automatically
- Use spawn in CI/CD pipelines and automation scripts
- Pass prompts via command line or file
Changes:
- TypeScript CLI: Parse --prompt/-p and --prompt-file flags
- Security: Add validatePrompt() to prevent command injection
- Commands: Pass prompt via SPAWN_PROMPT env var to bash scripts
- Bash scripts: Detect SPAWN_PROMPT and fork interactive/non-interactive
- Help text: Document new flags with examples
Implementation:
- claude.sh: Use 'claude -p' for non-interactive execution
- aider.sh: Use 'aider -m' for non-interactive execution
- shared/common.sh: Add execute_agent_non_interactive() helper
Security:
- Validates prompts for command injection patterns
- Length limit: 10KB max
- Blocks $(), backticks, piping to bash/sh
- Uses printf %q for proper shell escaping
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* docs: Add testing guide for non-interactive mode
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>