fix: the images backup carried the key to the accounts it backs up (4234)
CI / lint (push) Successful in 3s
CI / extension-version (push) Successful in 3s
Build images / sign-extension (push) Successful in 4s
Build images / build-agent (push) Successful in 7s
CI / frontend-build (push) Successful in 23s
CI / backend-lint-and-test (push) Successful in 33s
Build images / build-web (push) Successful in 57s
Build images / smoke-web (push) Skipped
Build images / build-ml (push) Successful in 1m49s
Build images / promote (push) Skipped
CI / integration (push) Successful in 2m20s
CI / lint (push) Successful in 3s
CI / extension-version (push) Successful in 3s
Build images / sign-extension (push) Successful in 4s
Build images / build-agent (push) Successful in 7s
CI / frontend-build (push) Successful in 23s
CI / backend-lint-and-test (push) Successful in 33s
Build images / build-web (push) Successful in 57s
Build images / smoke-web (push) Skipped
Build images / build-ml (push) Successful in 1m49s
Build images / promote (push) Skipped
CI / integration (push) Successful in 2m20s
Listing a 2026-05 tarball while investigating the 4.3T `_backups` pile showed
its second and third entries:
images/secrets/
images/secrets/credential_key.b64
That is the key that decrypts the stored Patreon/SubscribeStar session
credentials, and `cookies/` sat beside it — both unexcluded, so this was true
of every images backup taken today, not just the old ones. An images tarball
is supposed to be a media archive; one that carries the operator's account
keys is a credential leak wearing a backup's name, in a single file that is
easy to copy to another disk or restore somewhere less protected. Encryption
at rest buys nothing when the key travels in the same archive.
`secrets` and `cookies` join `_backups` and `_quarantine` in one named tuple,
each with its reason recorded — the recursion that produced 4.3T of nested
tarballs is the cautionary tale for why the list is worth explaining rather
than just listing.
A restore no longer re-establishes credentials. You sign in again, which is
the correct outcome for a media backup.
Tests cover both new names and that every exclude stays root-relative — a bare
`secrets` would also match an artist folder of that name.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
This commit is contained in:
@@ -24,6 +24,25 @@ from pathlib import Path
|
||||
|
||||
_BACKUPS_DIRNAME = "_backups"
|
||||
|
||||
# Excluded from the images tarball, and each for its own reason (#4233, #4234):
|
||||
#
|
||||
# _backups — the archive would otherwise contain every previous archive.
|
||||
# This is not hypothetical: the 2026-05-23/24 runs, taken before
|
||||
# this exclude existed, grew 43G -> 107G -> ... -> 2123G as each
|
||||
# swallowed its predecessors, and cost 4.3T of the images
|
||||
# filesystem until they were reclaimed on 2026-09-21.
|
||||
# _quarantine — holds files deliberately pulled OUT of the library.
|
||||
# secrets — `credential_key.b64`, the key that decrypts the stored
|
||||
# Patreon/SubscribeStar session credentials.
|
||||
# cookies — those session cookies themselves.
|
||||
#
|
||||
# The last two are the ones worth stating plainly: an images tarball is a media
|
||||
# archive, and a media archive that carries the key to the operator's accounts
|
||||
# is a credential leak wearing a backup's name. Encryption at rest buys nothing
|
||||
# when the key rides along in the same file. A restore therefore does NOT
|
||||
# re-establish credentials — you sign in again, which is the correct outcome.
|
||||
_IMAGES_EXCLUDED_DIRNAMES = ("_backups", "_quarantine", "secrets", "cookies")
|
||||
|
||||
# Subprocess-level guardrails BEYOND the Celery soft_time_limit. The Celery
|
||||
# soft limit signals the Python process; subprocess.Popen in a blocking syscall
|
||||
# ignores that signal, so these bound the worst case directly. Each sits just
|
||||
@@ -173,8 +192,10 @@ def backup_images(
|
||||
[
|
||||
"tar", "--zstd", "-cf", str(tar_path),
|
||||
"-C", str(images_root.parent), images_root.name,
|
||||
f"--exclude={images_root.name}/_backups",
|
||||
f"--exclude={images_root.name}/_quarantine",
|
||||
*(
|
||||
f"--exclude={images_root.name}/{name}"
|
||||
for name in _IMAGES_EXCLUDED_DIRNAMES
|
||||
),
|
||||
],
|
||||
_IMAGES_SUBPROCESS_TIMEOUT_S,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user