laravel-workkit/config
Fabian Wagner 40901c0f5e fix(backup): stream through openssl pipe — kills 500MB+ memory exhaustion
The pre-1.1.1 pipeline ran each stage as a separate file step:
  mysqldump → file.sql
  xz → file.sql.xz  (read whole file into memory)
  Crypt::encryptString(file_get_contents(file.sql.xz))
The third step blew up with "Allowed memory size exhausted" on
mid-three-digit-MB compressed dumps because Laravel's Crypt envelope
reads the whole input, base64-encodes (+33%), and JSON-wraps it for
the MAC. Peak memory was ~3.5× the file size.

New pipeline is one shell pipe:
  bash -c 'set -o pipefail; mysqldump | xz -3 | openssl enc \
    -aes-256-cbc -pbkdf2 -iter 600000 -salt -pass env:WK_KEY > out'

Zero PHP-side allocation for the payload — the encryption runs in the
openssl process, not the PHP heap. The output file format is the
standard `openssl enc -salt` format (starts with "Salted__"), so it's
also restorable with vanilla openssl on any host:
  openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 -pass env:K \
    -in backup.sql.xz.enc | xz -d | mysql ...

Encryption is still APP_KEY-derived: the base64-stripped APP_KEY is
fed to openssl as the passphrase, PBKDF2 (600k iters) stretches it
into the AES key. A backup is still only restorable by a deployment
that knows the same APP_KEY.

Other changes:
- xz default level dropped from 9 to 3 (tunable via --xz-level or
  config('workkit.backup.xz_level')). For SQL dumps -9 buys a few %
  size at multiples of the time cost; -3 is the sweet spot.
- Restore detects and rejects pre-1.1.1 Crypt-format backups with a
  clear error (those need a one-off Crypt::decryptString, which would
  hit the same memory wall, so we don't auto-fall-back).
- "bad decrypt" / "bad magic" stderr now translates to "APP_KEY
  mismatch" so operators don't have to recognise openssl errors.

Verified end-to-end against the dev DB (981 blogs / 659 users / 209
roles): backup in 1.2s, openssl-format output, restore into throwaway
DB matches every spot-checked row count.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 14:26:17 +02:00
..
workkit.php fix(backup): stream through openssl pipe — kills 500MB+ memory exhaustion 2026-04-29 14:26:17 +02:00