v2.0.4-hardening: fuzz suite + integration tests + production readiness
Phase 8 of v2.0. Final hardening pass before production tag. Path-guard fuzz suite (34 tests): traversal attacks (../ all depths, encoded %2e%2e, null bytes, absolute escapes, prefix-without-separator, backslash), secret-file deny list (.env, *.pem, id_rsa*, *.key, credentials.json, *.kdbx, .netrc), valid-path positives, edge cases (empty, whitespace, very long, triple-dot, multiple slashes). write_guard.ts hardened: added null-byte rejection and whitespace-only rejection (previously only checked empty string). Pending-changes integration test skeleton: 4 tests covering the full queue→apply→rewind cycle against a real DB + filesystem. Gated on DATABASE_URL via describe.runIf (same pattern as apps/server's tool_cost_stats.test.ts). Skips cleanly when unset. 57 tests passing (23 existing + 34 fuzz), 4 integration skipped. All builds clean. All services healthy. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -54,10 +54,14 @@ export function isSecretPath(filePath: string): boolean {
|
||||
* checks the result stays within projectRoot.
|
||||
*/
|
||||
export function resolveWritePath(projectRoot: string, filePath: string): string {
|
||||
if (!filePath || filePath.length === 0) {
|
||||
if (!filePath || filePath.trim().length === 0) {
|
||||
throw new WriteGuardError('file path is required');
|
||||
}
|
||||
|
||||
if (filePath.includes('\x00')) {
|
||||
throw new WriteGuardError('file path contains null byte');
|
||||
}
|
||||
|
||||
const candidate = filePath.startsWith('/') ? filePath : resolve(projectRoot, filePath);
|
||||
const normalized = resolve(candidate); // normalizes ../ segments
|
||||
|
||||
|
||||
Reference in New Issue
Block a user