mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-08 01:43:55 +00:00
37b12379c1
* fix(stacks): refuse file-explorer delete/rename/chmod on protected stack files Previously the per-stack file explorer treated PROTECTED_STACK_FILES (compose.yaml, compose.yml, docker-compose.yaml/.yml, .env) as a UI hint only. A direct API call from any user with stack:edit could delete or rename compose.yaml and break the stack irrecoverably because the next deploy would fail to find a compose file and the write was unrecoverable without a DB backup. The frontend DeleteFileConfirm enforced a type-to-confirm gate but a stale UI or a scripted client bypassed it. FileSystemService now refuses the destructive ops at the service layer with a new PROTECTED_FILE error code that the route layer surfaces as 409. The compose-editor save path (PUT /files/content) and the upload-overwrite path (POST /files/upload writing a same-named file) remain unblocked because both are legitimate ways to update compose.yaml. Tests pin the allowed paths so a future tightening can not silently regress them. The protection is scoped to entries at the stack root; subdirectory files happen to share a protected name (e.g., a snapshot under backups/compose.yaml) are not blocked because compose CLI only reads the root file. A trailing-slash bypass is closed by stripping trailing separators before the basename check. Frontend DeleteFileConfirm needs no change. Its existing toast.error surface renders the friendly server message. * fix(stack-files): drop polynomial regex from protected-file helpers CodeQL js/polynomial-redos flagged the /\/+$/ pattern used to strip trailing slashes from relPath in isProtectedRelPath and protectedFileError. The regex is bounded in practice (the upstream validator rejects '//' anywhere in the path) but the static analyzer cannot follow that dataflow guarantee and would have flagged any future caller that skips the validator. Replace the two callsites with a small stripTrailingSlash helper that uses endsWith + slice. Bounded O(1), no regex, no analyzer alert. The inline comment documents the upstream invariant so a future reader does not reintroduce the /+ quantifier.