Skip to content

fix(file-browser): preserve group permissions for shared storage - #2546

Merged
Seiger merged 2 commits into
evolution-cms:3.6.xfrom
MiddleSokilAI:sokil/fix-shared-browser-access-36
Nov 2, 2026
Merged

Seiger merged 2 commits into
evolution-cms:3.6.xfrom
MiddleSokilAI:sokil/fix-shared-browser-access-36

Conversation

@MiddleSokilAI

@MiddleSokilAI MiddleSokilAI commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

A deployment can keep uploads outside the release tree while exposing each upload type through a site-side symlink. The dashboard currently reports the configured shared root as invalid. More seriously, the media browser loses the file_groups key for files outside filemanager_path and treats an unresolved key as public.

This targets 3.6.x and changes only the browser access helpers, browser guards, dashboard diagnostics and regression tests.

Changes

  • Preserve existing ACL keys such as assets/images/private when the configured browser URL identifies a site-side directory whose real path exactly matches the physical type root.
  • Refuse and log unresolved ACL identities for non-admin managers when use_udperms is enabled, covering listings, direct reads, writes, recursive reads, descendant checks and inert link metadata.
  • Accept a proven shared browser root in the dashboard; retain warnings for missing or unmapped roots. Check filemanager_path independently instead of accidentally reading rb_base_dir.
  • Keep descendant symlinks, traversal and unsafe path names refused. No permission checks or thumbnail-link guards are disabled.

Verification

  • PHP 8.4.27, Laravel 13.38.0, Pest 5.3.4: vendor/bin/pest tests/Unit/Security tests/Unit/SystemSettingPathNormalizerTest.php — 1116 passed, 8 skipped, 3884 assertions.
  • Full core suite in CI: PHP 8.4 and 8.5 — 2407 passed, 8 skipped each; PHP 8.6 RC — 2406 passed, 9 skipped. All use strict warning/risky/deprecation failure flags.
  • PHPStan passes on PHP 8.4 and 8.5. MySQL, PostgreSQL and SQLite installs, ZIP smoke checks and dependency audit pass. The audit was retried after a Packagist connection timeout.
  • Updated the inherited ACL source assertion to accept aclRoot() cached in a local variable while retaining the site-wide-root requirement.
  • Git whitespace checks passed.

The local fixture executes the actual dashboard include and browser guards against temporary release/shared directories and SQLite group restrictions. The unmodified 3.6 browser allows a non-member to read the restricted fixture file; the patched browser refuses it while allowing the group member. It also verifies stable keys across releases and personal roots, new-file paths, directory listings, direct access, recursive reads, refusal logging, URL mapping, device names and thumbnail symlink containment.

Compatibility

With group permissions enabled, a non-admin using an external root without a verifiable site-side filesystem alias now receives a refusal rather than public access. Existing ACL rows are retained; there is no database migration or dependency update. Production has not been changed.

Local before/after proof

Local Evolution 3.6 regression fixture before and after the fix

Local reproduction only: dashboard messages come from the real configuration-check include; the access results come from the real browser guards. No production data is shown.

@Seiger
Seiger merged commit 9e52db5 into evolution-cms:3.6.x Nov 2, 2026
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants