chmod has no legitimate use case in Fileshed context:
- File permissions are managed by Fileshed's own system (zones, groups, modes)
- Unix permissions are never exposed to users via the API
- Allowing chmod creates a security risk (executable scripts)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update version in Fileshed.py
- Update README badges (version + tests count 1195)
- Update Exec_tests.md version
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- C3: FS/DB atomicity with rollback on shed_rename, orphan cleanup in shed_maintenance
- C4: SQLite WAL mode for better concurrent read/write performance
- C5: Git lock (fcntl.flock) for group operations to prevent index corruption
- C6: SQLite retry with exponential backoff (3 retries, 0.1/0.2/0.4s delays)
Also: Change xxd to od in README features (xxd not in container)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- shed_create_file: Add pedagogical hint explaining it's a wrapper
- SQL security: Convert query to uppercase before pattern matching (fixes case bypass)
- Tests: Add 5 SQL security tests (1087-1091) for case-insensitive validation
- Docs: Fix function count (37→38), add shed_create_file to SPEC.md
- README: Update test badge (1086→1091)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New function: shed_create_file(zone, path, content, file_type='text')
- Simplest way to create/overwrite a file
- Supports both text and bytes (file_type parameter)
- For bytes: content_format='hex', 'base64', or 'raw'
- Delegates to shed_patch_text/bytes with overwrite=True
Also added overwrite parameter to shed_patch_bytes for consistency
with shed_patch_text.
Function count: 37 → 38
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When overwrite=True, the position parameter is ignored anyway.
Now we skip position validation when overwrite=True, preventing
errors when LLMs confuse the parameter with a position value.
Also added explicit warning in tips:
"⚠️ overwrite is a PARAM (overwrite=True), NOT a position value"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SEC-01: Remove internal paths from error messages
- Remove uploads_dir from FILE_NOT_FOUND details (exposed internal paths)
ROB-01: Add context to generic exception messages (36 occurrences)
- Each "An unexpected error occurred" now describes the operation
- Examples: "Unexpected error during ZIP extraction",
"Unexpected error while editing text file", etc.
This helps LLMs understand which operation failed without exposing
sensitive system information.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Validates parameter types before use to prevent TypeError/AttributeError
when LLMs pass wrong types (e.g., "" instead of None, 0 instead of ""):
- max_output, timeout: validate int type
- line, end_line: validate int type in shed_patch_text
- offset, length: validate int type in shed_patch_bytes and shed_hexdump
- regex_flags: validate string type
- to (shed_convert_eol): validate string type
Each error message includes:
- Parameter name
- Received value with type
- Expected format
- Concrete example in hint
Also adds LLM Guardrails section to SPEC.md explaining the rationale:
minimize round-trips by making errors self-correcting.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. shed_patch_text: Skip line/end_line/pattern validation when overwrite=True
2. shed_patch_bytes: Only validate offset bounds when position uses it (at/replace)
3. shed_lockedit_overwrite: Add explicit validation that content is not None
4. shed_sqlite: Reject contradictory import_csv + query parameters
These parameters were being validated even when ignored, causing unnecessary
errors when LLMs pass default values like end_line=0 or pattern="".
https://claude.ai/code/session_0126dD9QeVgoFVT7ZBxbnhNM
Add _strip_sql_comments() to remove /* */ and -- comments before
checking for dangerous SQL patterns (ATTACH, DETACH, LOAD_EXTENSION).
This prevents bypass attacks like AT/**/TACH.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Verify ZIP file headers (PK signature) before extraction/info
- Add CSV_MAX_COLUMNS = 5000 limit to prevent DoS with wide files
- New constants: ZIP_MAGIC_BYTES, CSV_MAX_COLUMNS
- New error code: CSV_TOO_WIDE
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Refactor 6 functions to use _resolve_zone(): shed_tree, shed_zipinfo,
shed_file_type, shed_convert_eol, shed_hexdump, shed_link_create
- Add group zone support to shed_zipinfo, shed_file_type, shed_hexdump,
shed_convert_eol
- Replace subprocess 'which' with shutil.which() in _check_command_available
- Remove printenv and envsubst from whitelist (expose env variables)
- Add symlink check before ZIP extraction (TOCTOU protection)
- Add large_files to tool description howto list
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused Callable import (line 78)
- Remove redundant shutil import in _neutralize_git_hooks
- Cache content.encode('utf-8') result in _validate_content_size
- Cache zf.infolist() result in shed_unzip ZIP bomb protection
- Cache zf.namelist() result before extraction in shed_unzip
- Cache items[:100] slice in build_tree function
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
- shed_lockedit_open: Clean up orphaned editzone file on copy failure
before releasing lock
- shed_unzip: Clean up directories (not just files) on partial extraction
failure, using reverse-sorted order for nested directory cleanup
- shed_exec git clone: Add fallback repo_name="repository" for malformed
URLs that would result in empty repo name
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
CRITICAL fixes:
- _check_lock_owner: Catch OSError/PermissionError when reading lock file
- _acquire_lock: Ensure complete write with partial write detection and
cleanup of corrupt lock file on failure
- _acquire_lock race path: Catch OSError/PermissionError when reading
existing lock, and handle write failure with proper StorageError
HIGH fix:
- SQL queries with limit=0: Use fetchmany() with batching up to
MAX_SQL_ROWS (10000) to prevent memory exhaustion on large result sets
Added constant:
- MAX_SQL_ROWS = 10000 for SQL query protection
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
- Replace all `except Exception as e:` with `except Exception:` where
the exception variable `e` was not used (36 occurrences)
- Replace `except ImportError as e:` with `except ImportError:` (1 occurrence)
The exception is intentionally not captured to avoid any potential
information leakage and to clarify that only generic error messages
are returned to users.
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
- CRITICAL: Fix lock leak in shed_lockedit_cancel - ensure lock is always
released via try-finally even if editzone cleanup fails
- HIGH: Add user_id validation in _get_user_root - validate non-empty
string and UUID format (8-4-4-4-12 hex pattern)
- HIGH: Catch FileNotFoundError in _git_run when git is not installed
- HIGH: Catch OSError/PermissionError in _git_run for subprocess failures
- Remove command details from TimeoutExpired error (info leakage)
- Add UUID_PATTERN constant for efficient validation
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
Critical fixes:
- L3625: Remove {e} from regex error message → generic message with hint
- L3857: Remove {e} from content error message → generic message with hint
High priority fixes:
- L2748: Remove path from FILE_LOCKED error details
- L4529: Remove path from PERMISSION_DENIED (delete) error details
- L4606: Remove path from PERMISSION_DENIED (rename) error details
- L4682: Remove path from PERMISSION_DENIED (lockedit) error details
All error messages now return minimal information to prevent
information disclosure about internal state or other users' activities.
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
Security fixes:
- Replace bare except with except Exception at L4691
- Sanitize str(e) in ~35 error responses to prevent info leakage
- Remove sensitive data (user_id, conv_id) from lock error messages
- Add None-safety to _get_user_root, _get_conv_id, _resolve_zone
Robustness fixes:
- Add cleanup for partial ZIP extraction on error
- Define module-level constants (BYTES_PER_MB, ZIP_MAX_*, etc.)
Code quality:
- Move ZIP bomb limits to module constants
- Use MAX_HEXDUMP_BYTES constant instead of magic number
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
- _patch_text_impl: Move editzone operations inside try block so lock
is released by finally if mkdir/copy/touch fails after acquisition
- _patch_bytes_impl: Same fix as _patch_text_impl for binary patching
- shed_lockedit_open: Wrap post-lock operations in try/except to release
lock on failure (mkdir, copy to editzone)
- shed_lockedit_save: Use try/finally after successful copy to ensure
lock is released even if git commit or cleanup fails
These fixes prevent locks from being permanently stuck when errors occur
between lock acquisition and the main try block.
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
Security fixes:
- Add explicit symlink detection in _resolve_chroot_path
- Fix TOCTOU race conditions in _patch_text_impl and _patch_bytes_impl
- Sanitize SQLite error messages to prevent information leakage
- Add finally:conn.close() to prevent SQLite connection leaks
- Add readonly check for output_csv in shed_sqlite
Code quality:
- Replace bare except with specific exceptions (OSError, UnicodeDecodeError, etc.)
- Translate French comments to English in shed_import
- Refactor shed_sqlite to use centralized _resolve_zone()
API improvements:
- Change safe=False to safe=True by default in patch_text/patch_bytes
- Change message='' to message=None in zone movement functions
Documentation:
- Add comprehensive error codes reference table to SPEC.md
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
Updated functions with allow_zone_in_path parameter and zone_name validation:
- shed_tree (path)
- shed_zipinfo (path)
- shed_file_type (path)
- shed_hexdump (path)
- shed_force_unlock (path - both group and personal zones)
- shed_group_set_mode (path)
- shed_group_chown (path)
Also fixed zone_name consistency:
- Changed "group:{id}" to "Group:{id}" in _patch_text_impl and _patch_bytes_impl
- Changed "group:{group}" to "Group:{group}" in shed_copy_to_group
All zone names now consistently use capital letters (Storage, Documents,
Uploads, Group:) for internal discipline while accepting case-insensitive
input from users.
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
Extended zone_name validation to:
- shed_move_uploads_to_storage
- shed_move_uploads_to_documents
- shed_copy_storage_to_documents
- shed_move_documents_to_storage
These functions previously had NO path validation and could create
duplicate zone folders (e.g., Storage/Storage/file.txt).
Also updated shed_help documentation to list all functions supporting
allow_zone_in_path parameter.
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
Extended zone_name validation to:
- All 5 lockedit_* functions (open, exec, overwrite, save, cancel)
- shed_copy_to_group (validates both src_path and dest_path)
Also updated shed_help paths documentation to include lockedit_* in
the list of functions supporting allow_zone_in_path.
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
Refactored path validation to detect when paths start with the zone name
(e.g., "Documents/folder" in zone="documents"), which causes unwanted
directory duplication. The validation rejects such paths by default with
a helpful error message.
Changes:
- Added zone_name and allow_zone_in_path params to _validate_relative_path
- Refactored _validate_path_args to call _validate_relative_path
- Extracted _is_expression_not_path helper for cleaner code
- Updated shed_exec, shed_patch_text, shed_patch_bytes, shed_delete,
shed_rename to pass zone context and allow_zone_in_path parameter
- Updated _patch_text_impl and _patch_bytes_impl accordingly
LLMs can now set allow_zone_in_path=True if they intentionally want a
subfolder named after the zone.
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
LLMs often mistakenly include the zone name in paths (e.g., zone="Documents"
with args=["Documents/folder"]) creating unwanted duplicate folders. Added
detailed explanation with concrete examples showing the mistake and its
consequence.
https://claude.ai/code/session_01THb4YA4SqYG52LVwjwb5Uo
Warn users that files imported to Uploads are permanent and NOT deleted
when the conversation is deleted. They must be removed manually with
shed_delete(zone='uploads', path='...').
https://claude.ai/code/session_01DLaRR2nnTryPWd2p7MyUtf
Remind users that the source ZIP file remains in Uploads after extraction,
that Uploads files are NOT deleted when the conversation is deleted,
and suggest using shed_delete to remove it manually.
https://claude.ai/code/session_01DLaRR2nnTryPWd2p7MyUtf
Use canonical zone names with capital letters (Uploads, Storage, Documents)
in documentation, hints, and response data for consistency with the rest
of the codebase.
https://claude.ai/code/session_01DLaRR2nnTryPWd2p7MyUtf
Allow extracting ZIP files from Uploads zone without moving them first.
The new src_zone parameter accepts "uploads", "storage", or "documents"
while zone parameter remains the destination (storage/documents only).
Bump version to 1.0.2.
https://claude.ai/code/session_01DLaRR2nnTryPWd2p7MyUtf