* security: path traversal, query bounds, marker injection fixes
LocalStorage: contained() method validates all paths stay within storage root.
file-resolver: resolveFile validates filePath within brainRoot, marker prefix
rejects ../, absolute paths, bare '..'. file_list: LIMIT 100 on slug-filtered
branch + FILE_LIST_LIMIT constant for both branches.
Co-Authored-By: Gus <garagon@users.noreply.github.com>
* security: symlink hardening in all file walkers
All 4 walkers in files.ts (collectFiles, findRedirects, findAndClean, scan)
plus init.ts counter now use lstatSync + isSymbolicLink skip. Tests import
production collectFiles instead of reimplementing it. node_modules skipped.
CLI file list and verify queries bounded with LIMIT.
Co-Authored-By: Gus <garagon@users.noreply.github.com>
* feat: typed health check DSL + recipe migration
4 DSL types: http, env_exists, command, any_of. Replaces raw execSync
on recipe YAML. All 7 first-party recipes migrated from shell strings
to typed objects. String health_checks still accepted with deprecation
warning + metachar validation for non-embedded recipes. isUnsafeHealthCheck
blocks shell injection for user-created recipes.
Co-Authored-By: Gus <garagon@users.noreply.github.com>
* chore: bump version and changelog (v0.9.3)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: E2E test for file_list LIMIT enforcement against real Postgres
Inserts 150 file rows for one slug, verifies file_list returns at most
100 (both slug-filtered and unfiltered branches). Proves the LIMIT
works at the database level, not just in unit tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Gus <garagon@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>