tomatophp/filament-browser
A Filament plugin that adds a full file and folder browser with a built-in code and markdown editor, plus previews for images, video, audio, PDF, and Excel files. It supports creating, renaming, and deleting files, and is intended for super-admins only.
PM framing. This is not a product feature; it is a privileged operator console shipped inside the admin panel. It mounts a file/folder/media browser over the server filesystem with in-place code and Markdown editing, upload, rename, delete, and inline previews (image, video, audio, PDF, Excel, Markdown). Every downstream decision — owner, environment scope, access model, audit — should follow from that framing. It is a replacement for SSH/FTP, and should be evaluated as such, not as a UI component.
Architecture fit
AdminPanelProvider via FilamentBrowserPlugin::make(), inherits panel auth/routing/Livewire, and introduces no new service, datastore, queue, or sidecar. Operationally that is close to zero new surface area to run.mv/nano, or remote SSH — one auditable-in-principle surface instead of many out-of-band ones (in principle, because the package ships no audit log; we must add it).basePath(base_path()) — the entire application tree. A TPM's first job is to force the root down to a purpose-built directory (e.g. a content or imports directory, or a /storage/app/browser sandbox) before anything is installed in a shared environment.Integration feasibility
composer require tomatophp/filament-browser, php artisan filament-browser:install, register the plugin with fluent config (basePath, hiddenFolders, hiddenFiles, hiddenExtensions, per-action allow* flags, authorize()). Config/views/lang/migrations are publishable but optional; core function needs no migrations, so the code-level blast radius is low and reversible.Technical risk (ranked)
| # | Risk | Severity | TPM mitigation |
|---|---|---|---|
| R1 | Privileged filesystem write reachable from a web admin panel | High | v5.0.0 adds real hardening (realpath confinement, rejection of ../absolute paths/null bytes/symlink escapes, server-side re-validation of every allow* on each Livewire request). Still require written security sign-off, a narrow basePath, and writes disabled by default in production. |
| R2 | Access gate is a shared password in .env (DEVELOPER_GATE_PASSWORD) |
High | The authorize() callback is the actual control plane. Make it a go-live blocker: SSO group + environment tag + optional IP/time window. Treat the shared password as defence-in-depth only, and rotate it. |
| R3 | No audit trail, recycle bin, or undo | High | The package provides none. Mandate external logging of file operations (Livewire/Filesystem event listener or filesystem-level audit) and snapshot/backup coverage of the configured root. Consider disabling delete/overwrite until audit exists. |
| R4 | Bus factor: one maintainer, 0 dependents, 43 stars | Medium-High | Name an individual owner who accepts the dependency in writing; budget for fork or vendored copy; document the exit path. |
| R5 | Security history is reactive (v1.0.1 "fix security issue", v2.0.3 route fix, v5.0.0 hardening overhaul) | Medium | Direction of travel is positive but undisciplined. Pin versions, subscribe to releases, quarterly review. |
| R6 | Breaking changes at v5: legacy JSON route/controller/JS bundle removed; creagia/filament-code-field replaced by Filament's CodeEditor; .env hidden by default; embedded previews replace public-storage copies |
Medium | Run a compatibility gate before upgrading; grep for the removed route; audit any published view overrides; treat hideEnvFiles(false) as a security exception requiring approval. |
| R7 | Published config/views/lang create upgrade drift | Low-Medium | Publish only what must be overridden; keep an override register. |
| R8 | Licensing/procurement | Low | MIT — no legal friction, no commercial support contract to negotiate (and none available). |
Key questions to resolve before commitment
base_path()?authorize() check in our org — SSO group, environment, ticket reference, IP range, time window?v3 branch and staff a divergent, lower-support track?Stack fit
Settings group and integrates with tomatophp/filament-plugins, so it lands in an existing plugin-management surface rather than as a bespoke carve-out — provided we already use that convention.Migration path There is no data migration; the migration is organisational — moving from out-of-band file operations (FTP/SFTP/SSH/CLI) to an in-panel workflow.
v3), not a version bump — accept explicitly that this is a lower-support, likely-to-divergе track and record the decision.Compatibility
creagia/filament-code-field at v5 — any local customisation built on the old field will break..env is hidden by default at v5; any team that needs it visible is creating a security exception, not a config toggle.php.ini realities: upload_max_filesize, post_max_size, max_execution_time, and available disk headroom all become user-facing constraints once uploads are exposed through the UI.Sequencing (recommended, ~6–8 weeks elapsed)
basePath, all hidden* lists populated, all allow* writes off. Verify read-only browse and previews.authorize() (SSO group + environment + optional time/IP), retire reliance on DEVELOPER_GATE_PASSWORD, and confirm the gate is re-checked on every Livewire request.allowEditFile/allowCreateNewFile/allowCreateFolder/allowRenameFile/allowDeleteFile in staging only; run the pilot use cases from the inventory.Maintenance
hidden*/allow* matrix as directories are added.Support
hiddenFolders/basePath/permissions issue), not package defects.allow* flags per environment, how authorize() evaluates, the shared-password rotation procedure, and where the audit log lives.Scaling
vendor/, node_modules/, or an unbounded uploads directory) will degrade the UX and possibly the request. Cap the root's size by design.Failure modes
| Failure | Blast radius | Detection | Response |
|---|---|---|---|
| Accidental delete/overwrite of a live file | High — no recycle bin, no undo | User report; audit log | Restore from snapshot/backup; verify backup coverage of the configured root before go-live |
| Compromised super-admin session | Very high — direct filesystem write | Anomalous audit entries | Narrow root + disabled production writes are the only real containment; have a revoke/rotate runbook |
basePath misconfigured to base_path() |
Very high — .env, keys, app code exposed |
Config review, drift check | Enforce config-as-code with a test asserting the root value |
Shared DEVELOPER_GATE_PASSWORD leaks |
High — bypasses per-user identity | Secret scanning | Rotate; ensure authorize() is the actual gate so the password alone is insufficient |
| Symlink/permission edge case lets a path escape the root | High | Pen-test / attempted traversal in review | Report upstream, patch locally, restrict root further |
| Upstream abandonment or breaking v6 | Medium — no dependents, so no community fix | Release feed goes quiet | Execute the documented fork/vendor exit path |
| PHP limits hit on large upload/preview | Low–Medium — user-facing errors | Error logs | Raise limits or exclude that file class via hiddenExtensions |
Ramp-up
allow* re-validation, authorize() on each Livewire request) well enough to defend it in a review. This is non-negotiable and should be scheduled, not assumed.authorize() semantics, audit location, restore procedure, exit path) plus the ADR. If those two documents don't exist, the adoption isn't finished regardless of whether the plugin renders.How can I help you explore Laravel packages today?