mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
fix(recovery): the database dumps count in the keys the backups still need
The recovery kit, "Keys the backups still need" and safeToDropRetiredKeys read only the stored copies and the off-host account objects. After a rotation the page called the old key safe to drop while every dump taken before it, the pre-migration dumps that are the way back from an update among them, could only be restored with that key: db-restore refuses a dump whose active key is missing. A dump now counts for the key its rows were written under, the manifest's active key: a dump on this server while it is kept (read from the manifests), an off-host one until the bucket's rule for database/ expires it, or indefinitely when that rule cannot be read. The nightly run records the key on its ledger row (migration 0489, database_backup_runs.active_key_id). The encryption view and the kit list the dumps per key, in every locale, and the rotation and backup runbooks say so.
This commit is contained in:
1 parent
40c310f0ad
commit
26a9efdf52
24 files changed
+422
-45
No files matched your search
@@ -44,6 +44,7 @@ function statusWith(configuredKeyCount: number) {
|
||||
stored: [],
|
||||
unrecorded: { copies: 0, oldestAt: null },
|
||||
offhost: [],
|
||||
dumps: [],
|
||||
offhostExpirationDays: null,
|
||||
retiredKeysStillNeeded: [],
|
||||
},
|
||||
|
||||
@@ -40,6 +40,8 @@ const need = (over: Partial<KitKey["need"]> = {}): KitKey["need"] => ({
|
||||
configured: true,
|
||||
storedCopies: 0,
|
||||
offhostUntil: null,
|
||||
localDumps: 0,
|
||||
offhostDumpsUntil: null,
|
||||
...over,
|
||||
});
|
||||
|
||||
|
||||
@@ -88,6 +88,11 @@ interface EncryptionStatus {
|
||||
lastWrittenAt: string;
|
||||
neededUntil: string | null;
|
||||
}>;
|
||||
dumps: Array<{
|
||||
keyId: string;
|
||||
local: number;
|
||||
offhost: { lastWrittenAt: string; neededUntil: string | null } | null;
|
||||
}>;
|
||||
offhostExpirationDays: number | null;
|
||||
retiredKeysStillNeeded: string[];
|
||||
};
|
||||
@@ -306,9 +311,39 @@ export function EncryptionSection() {
|
||||
})}
|
||||
</li>
|
||||
))}
|
||||
{s.backups.dumps.map((row) => (
|
||||
<li key={`dump-${row.keyId}`}>
|
||||
{[
|
||||
row.local > 0
|
||||
? t("admin.section.encryption.backupsDumpLocalLine", {
|
||||
key: row.keyId,
|
||||
count: row.local,
|
||||
})
|
||||
: null,
|
||||
row.offhost
|
||||
? row.offhost.neededUntil
|
||||
? t("admin.section.encryption.backupsDumpOffhostLine", {
|
||||
key: row.keyId,
|
||||
when: fmt.dateTime(row.offhost.lastWrittenAt),
|
||||
until: fmt.dateTime(row.offhost.neededUntil),
|
||||
})
|
||||
: t(
|
||||
"admin.section.encryption.backupsDumpOffhostLineUnknown",
|
||||
{
|
||||
key: row.keyId,
|
||||
when: fmt.dateTime(row.offhost.lastWrittenAt),
|
||||
},
|
||||
)
|
||||
: null,
|
||||
]
|
||||
.filter((line): line is string => line !== null)
|
||||
.join(" ")}
|
||||
</li>
|
||||
))}
|
||||
{s.backups.stored.length === 0 &&
|
||||
s.backups.unrecorded.copies === 0 &&
|
||||
s.backups.offhost.length === 0 ? (
|
||||
s.backups.offhost.length === 0 &&
|
||||
s.backups.dumps.length === 0 ? (
|
||||
<li className="text-muted-foreground">
|
||||
{t("admin.section.encryption.backupsNone")}
|
||||
</li>
|
||||
|
||||
@@ -138,6 +138,20 @@ function KeyNeeds({ k }: { k: KitKey }) {
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (k.need.localDumps > 0) {
|
||||
lines.push(
|
||||
t("admin.recoveryKit.need.localDumps", { count: k.need.localDumps }),
|
||||
);
|
||||
}
|
||||
if (k.need.offhostDumpsUntil === "unknown") {
|
||||
lines.push(t("admin.recoveryKit.need.offhostDumpsUnknown"));
|
||||
} else if (k.need.offhostDumpsUntil) {
|
||||
lines.push(
|
||||
t("admin.recoveryKit.need.offhostDumpsUntil", {
|
||||
date: fmt.date(new Date(k.need.offhostDumpsUntil)),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
lines.push(t("admin.recoveryKit.source", { variable: k.source }));
|
||||
return <p className="text-muted-foreground text-xs">{lines.join(" ")}</p>;
|
||||
|
||||
Reference in new issue
Block a user