fix(offhost): judge the bucket's rules for database/ against this instance's folder

The dumps now live under database/<host of APP_URL>/, so the rule check reads
a sample key in that folder: a rule scoped to this instance's folder counts,
one scoped to another instance's does not.
This commit is contained in:
Marc-André Bombeck committed 2026-10-25 17:30:58 +01:00
1 parent a7691223fd
commit 2b79c01952
2 files changed
+36 -5

No files matched your search

@@ -3,7 +3,7 @@
* from the account copies: a rule scoped to another prefix, or to a tag, does
* not touch them.
*/
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import type { LifecycleRule } from "@aws-sdk/client-s3";
import { lifecycleFromRules, ruleAppliesTo } from "../offhost-lifecycle";
@@ -29,6 +29,25 @@ describe("lifecycle rules and the database dumps", () => {
).toEqual({ state: "configured", expirationDays: 14 });
});
it("reads the rules for this instance's own folder under database/", () => {
vi.stubEnv("APP_URL", "https://health.example.org");
try {
expect(
lifecycleFromRules([
rule(30, { Filter: { Prefix: "2026-" } }),
rule(9, { Filter: { Prefix: "database/health.example.org/" } }),
]).database,
).toEqual({ state: "configured", expirationDays: 9 });
expect(
lifecycleFromRules([
rule(9, { Filter: { Prefix: "database/staging.example.org/" } }),
]).database,
).toEqual({ state: "missing", expirationDays: null });
} finally {
vi.unstubAllEnvs();
}
});
it("says database/ is not covered when the only rule is scoped elsewhere", () => {
const result = lifecycleFromRules([
rule(30, { Filter: { Prefix: "2026-" } }),
+16 -4
View File
@@ -16,6 +16,10 @@
* without `s3:GetLifecycleConfiguration`, a target that does not implement the
* call, a network failure) and says nothing either way.
*/
import {
instanceIdFromEnv,
offhostObjectKey,
} from "@/lib/database-backup/dump-core.mjs";
import type { LifecycleRule } from "@aws-sdk/client-s3";
export interface LifecycleVerdict {
@@ -40,9 +44,17 @@ export const LIFECYCLE_MISSING: OffhostLifecycle = {
database: { state: "missing", expirationDays: null },
};
/** A key a database dump is stored under, to test the rules against. */
const DATABASE_SAMPLE_KEY =
"database/healthlog-20260101T013000Z-daily.dump.enc";
/**
* A key this instance's database dumps are stored under, to test the rules
* against: inside its own folder (`database/<host of APP_URL>/`), so a rule
* scoped to that folder counts and one scoped to another instance's does not.
*/
function databaseSampleKey(): string {
return offhostObjectKey(
"healthlog-20260101T013000Z-daily.dump.enc",
instanceIdFromEnv(),
);
}
/**
* Whether a rule's filter takes in `key`. Our objects carry no tags, so a
@@ -73,7 +85,7 @@ export function lifecycleFromRules(
return {
...verdict(rules),
database: verdict(
rules.filter((rule) => ruleAppliesTo(rule, DATABASE_SAMPLE_KEY)),
rules.filter((rule) => ruleAppliesTo(rule, databaseSampleKey())),
),
};
}