mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-18 03:54:17 +02:00
fix(backup): carry the owner across, or restored archives are invisible (#2656)
Neither _collect_archives nor _restore_archives touched created_by_id, so every restored archive row landed NULL. That column is not attribution, it is what the access check runs on: _ensure_archive_visible (api/routes/archives.py) fails closed on NULL — a 404 for any caller without archives:read_all — and the list paths filter created_by_id == user.id. On a multi-user instance the tally therefore reported archives restored while the person who owns them could neither list nor open them. Same shape as the deleted_at fix, and the same remedy: the collector records the key next to deleted_at, the restore mirrors the printer_id/project_id pattern exactly — one hoisted select(User.id), a membership test per row, an unknown id coerced to None rather than failing the row, and one de-duplicated note. It is in the overwrite setattr loop too, so overwrite keeps meaning "make local match the backup". Additive on the backup side, so older backups still restore; they just cannot know the owner. Clearing the id is not silent-safe, so the note says what it costs: those archives are visible only to users with archives:read_all until an admin reassigns them. Caveat recorded in a comment and raised in the PR, not decided here: this is the one place the module reuses a raw backup id, against its own rule. Validating it means a *stale* id clears rather than pointing somewhere wrong, but a live id belonging to a different person on a different instance would still collide. Collecting username and resolving on that would close it. 6 unit tests and 1 integration test that all fail against the parent commit, plus 2 controls that pass either way — a backup with no created_by_id key still restores, and a second operator still gets a 404.
This commit is contained in:
@@ -869,6 +869,13 @@ class GitHubBackupService:
|
||||
# deleted_at is what lets a restore put them back the way they
|
||||
# were instead of resurrecting them as visible archives.
|
||||
"deleted_at": str(a.deleted_at) if a.deleted_at else None,
|
||||
# Who owns the archive, for the same reason deleted_at is here:
|
||||
# it is not decoration, it is what the access check runs on.
|
||||
# _ensure_archive_visible (api/routes/archives.py) fails closed on
|
||||
# a NULL created_by_id and the list paths filter on it, so a
|
||||
# restored row without it is invisible to everyone but an admin —
|
||||
# while the restore reports it restored.
|
||||
"created_by_id": a.created_by_id,
|
||||
}
|
||||
archive_list.append(archive_data)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user