Storage Series Follow Ups - edmozley/freeitsm GitHub Wiki
Storage series - follow-ups and gaps
A working list to come back to once the storage series is complete. Started 13 November 2026, after PR #318 was merged.
The series, proposed and built by cloudcogsio, in order:
| What | State | |
|---|---|---|
| #283 / PR #318 | Files in S3-compatible storage, and safe moves | ✅ Merged with fixes in 5.2.0 - PR review · developer guide |
| #284 | System → Storage: ticket and change attachments, documents, screen recordings and War Room files, each with its own Server folder / S3 switch | ⏳ Design agreed, his to build |
| #293 | Files recycle bin | ⏳ Waiting |
| #285 | Files: make available offline | ⏳ Waiting |
| #286 | System → Backups and restore, with S3 as the offsite target | ⏳ Built on his fork, waits for #284 |
When to use this page: when the last of these is merged, go down the list below. Tick off what the series covered, and build what is left. Until then, check each new PR against it, so nothing here gets built twice.
1. Security of the connection
| # | Gap | Why it matters | Suggested fix | When |
|---|---|---|---|---|
| S1 | Plain http:// endpoints are allowed with no warning |
Needed for a MinIO on the LAN. But pointed at a public provider, the files themselves cross the internet unencrypted (the secret does not - requests are only signed with it) | A warning under the endpoint and on the Storage page when the scheme is http and the address is not private or local. A warning, not a block |
Now, or with #284 |
| S2 | No encryption-at-rest choice in the bucket | It relies on the provider's default. AWS encrypts by default now; some providers do not unless asked | A Server-side encryption choice (provider default / AES-256 / off) on the one S3 connection, sent as x-amz-server-side-encryption and signed |
With #284 |
| S3 | The permission is Files → Storage (sensitive), which the Files "manage everything" umbrella also grants | Whoever holds it can have every file copied to a bucket of their choosing, past the folder permissions. With #284 and #286 the same is true of every store and of the backups | A dedicated Storage and backups permission, never ticked by "Select all" or a preset, on System → Storage and System → Backups. Not administrator-only (Ed: that is overkill for configuring a backup target) | With #284 / #286 |
| S4 | Failed connection tests are not audited | Repeated tries against odd addresses leave no trace. Minor now that every request checks its address | An audit entry for each failed Test: endpoint, bucket, step and error, never the secret | Now |
2. Being told
| # | Gap | Why it matters | Suggested fix | When |
|---|---|---|---|---|
| N1 | Nobody is told when the storage location changes - it is only audited | Pointing storage at a new bucket copies every file there. It is the change an administrator most needs to hear about, as soon as it happens | A bell and an email to every administrator when a location changes, a move starts, old copies are removed, or a move ends. The same pattern as the API threat protection alerts | Now |
| N2 | The same for backups: target changed, passphrase changed, a backup or a restore started or finished | A restore replaces everything; a changed target sends everything elsewhere | Same bell and email | With #286 |
3. Watchtower
Already there: Watchtower's Background jobs card (Watchtower) appears whenever a job is failing, partly failing, stuck or overdue. That includes the storage move job (storage_migrate), and will include the backup job.
Not there yet - suggested as a Storage card, or lines on the Background jobs card. Shown only to people with the storage permission, and only when something is wrong:
| # | Shows | Source | When |
|---|---|---|---|
| W1 | Storage could not be reached - how many reads or writes failed in the last hour, and when it last worked | Nothing records this today: filesServeBytes() only writes to the server's error log. Needs a small counter or table (store, event, time), written when a StorageUnavailable is caught |
Now (Files), extended by #284 |
| W2 | A move has files that failed - "N files could not be copied", linking to the Storage tab | storage_migration_items where state = 'failed' |
Now |
| W3 | A move has stalled - no file copied for an hour while some are still pending | MAX(updated_datetime) against pending rows |
Now |
| W4 | Old copies waiting to be removed for more than N days - every file is stored twice | files_storage_previous set, nothing pending |
Now (amber, not red) |
| W5 | Storage is on http:// to a public address (S1) |
The saved settings | Now |
| W6 | Last backup failed, or none in its schedule plus a day | The backups history | With #286 |
| W7 | Last backup check (Verify) failed, or a backup has never been verified | The backups history | With #286 |
4. Smaller things from the PR #318 review
| # | Gap | Suggested fix |
|---|---|---|
| R1 | download.php / view.php send the recorded size_bytes, not the file's real size, so a truncated file answers with a Content-Length longer than what follows |
Ask the store for the size (size()) once, and answer 410 when they differ |
| R2 | Without ListBucket rights, S3 answers 403 rather than 404 for a missing key, so Skip cannot tell that a file is missing | Treat 403 on a HEAD for a key that was there before as "not found", or tell people in the help to grant ListBucket |
| R3 | Errors on the Storage tab use the browser's alert() |
The app's own message box, like the rest of Files |
5. To check when the series is complete
- Every store in System → Storage uses
storageLocationRelation()andstorageMigrateEnd(). None of them deletes on "unknown", or ends a move with a plainDELETE(the traps). - Every new outbound request (backups to S3 included) goes through
storageCheckedAddress()and pins the address. - A backup holds the encryption key - check how that key is protected in the backup, and that the restore page says what happens to secrets.
- Maintenance mode (#286) cannot be left on by a failed restore, and an administrator can always switch it off.
- The help, the user wiki and a developer guide exist for each part, plus a PR review page for each PR.
- Translations for every new string, before the release that carries it.
See also: Files storage - Developer Guide · Files S3 Storage - PR review · Watchtower