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() and storageMigrateEnd(). None of them deletes on "unknown", or ends a move with a plain DELETE (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