fix(backup): say when a restored archive lands without an owner (#2656)

`created_by_id` is not attribution, it is the column the access check runs
on: `_ensure_archive_visible` fails closed on NULL, so an ownerless archive
is a 404 for every caller without `archives:read_all` and never appears in
the ownership-scoped list queries.

On the overwrite path an absent key correctly leaves the local owner alone
— that rule is deliberate and unchanged. On the insert path there is no
local row to fall back on, so the archive lands ownerless, and nothing said
so. The restore reported N archives restored while the user who asked for
them saw none. Two ways in, both silent: a commit taken before the
collector recorded the column (every pre-#2656 backup), and an archive that
genuinely had no owner on the source instance.

Adds `archivesOwnerUnknown`, emitted on insert only, and suppressed when
the stale-id branch has already spoken for that row so one cause does not
produce two notes. Wording mirrors `archivesOwnerCleared` because the
consequence and the remedy are the same; the cause is not, so it is a
separate code rather than a reuse.

Five tests, plus the existing `test_a_backup_without_the_key_still_restores`
renamed and tightened — it asserted the silence this fixes. 13 locales back
in parity at 5772 leaves. No modal change: notes render through
`translateCoded`, which resolves by code.
This commit is contained in:
jmoore-skild
2026-08-04 08:57:35 -04:00
parent 329b506240
commit a85fa66dcc
15 changed files with 104 additions and 2 deletions
+20
View File
@@ -1017,6 +1017,7 @@ class GitHubRestoreService:
# column was added to fix) and silently un-delete a row the user
# deleted. So only carry a column the backup actually knows about;
# on insert, an absent key just takes the model default.
owner_cleared = False
if "created_by_id" in entry:
created_by_id = entry.get("created_by_id")
if created_by_id is not None and created_by_id not in valid_users:
@@ -1030,6 +1031,7 @@ class GitHubRestoreService:
"visible only to users with the archives:read_all permission until an admin reassigns them",
)
created_by_id = None
owner_cleared = True
fields["created_by_id"] = created_by_id
if "deleted_at" in entry:
# A soft-deleted archive is still in the backup (its row is kept
@@ -1065,6 +1067,24 @@ class GitHubRestoreService:
)
warned_files = True
# Insert-only, and the mirror of the "absent is not null" rule above:
# on overwrite an unknown owner correctly leaves the local one alone,
# but there is no local row here to fall back on, so the archive
# lands ownerless — a 404 for everyone without archives:read_all.
# Two ways to get here: a commit taken before the collector recorded
# the column (every pre-#2656 backup), or an archive that genuinely
# had no owner on the source instance. Both restore fine and both
# were silent, so the tally said "N archives restored" while the user
# who asked for them saw none. The stale-id case above already said
# its piece; don't say it twice for the same row.
if fields.get("created_by_id") is None and not owner_cleared:
tally.note(
"archivesOwnerUnknown",
"Some archives were restored without an owner — this backup does not record one, so they "
"are visible only to users with the archives:read_all permission until an admin reassigns "
"them",
)
row = PrintArchive(
filename=entry.get("filename") or "restored-from-backup",
file_path="",