Skip to content

test(e2e): backup → fresh-instance restore full-fidelity drill - #63

Merged
ProjectBay merged 1 commit into
mainfrom
test/backup-restore-fidelity-drill
Jul 10, 2026
Merged

test(e2e): backup → fresh-instance restore full-fidelity drill#63
ProjectBay merged 1 commit into
mainfrom
test/backup-restore-fidelity-drill

Conversation

@ProjectBay

Copy link
Copy Markdown
Owner

What this is

The data-safety proof needed before 1.0. A new e2e spec,
apps/openbucket-backend-e2e/src/backup-restore-fidelity.e2e-spec.ts, that
answers the real "will my data survive an upgrade" question.

The existing backup-restore.e2e-spec.ts restores WITHIN one running instance
and checks only object keys + bytes. This drill instead:

  1. Populates instance A with rich state (versioned bucket with 3 versions of
    a key; an object with user-metadata + tags + explicit Content-Type; an
    at-rest-encrypted object; a bucket with lifecycle + CORS + policy config).
  2. Takes a whole-instance backup .zip.
  3. Spawns a FRESH instance B — new DATA_DIR, fresh migrations, a
    different generated SSE key (asserted != A's), same root creds + admin.
  4. Restores the backup into B.
  5. Asserts rich fidelity on B, per dimension.

Uses the real spawn harness (two instances, ports 9280/9281) — no mocks.

What actually survived vs. the gaps found

SURVIVES (faithfully round-trips into B):

  • Current object bytes — byte-exact (doc.txt, rich.json, secret.bin).
  • Content-Type (S3 HEAD).
  • User-metadata — carried by the manifest, re-applied on restore, present on B's
    row (asserted via the admin metadata endpoint; see caveat below).
  • Object tags (S3 GET ?tagging).
  • Bucket versioning status (Enabled).
  • At-rest SSE round-trip across DIFFERENT instance keys — the backup stores
    DECRYPTED bytes, so B serves the original plaintext even though B generated its
    own SSE key. The bytes are not lost when the instance key changes.

GAPS — asserted as ACTUAL (lossy) behavior; candidate 1.0 data-loss surfaces:

  • Prior object versions are DROPPED. A had 3 versions of doc.txt; only the
    current pointer row is backed up (objectRepo.listByPrefix), so B has exactly
    1. Version history does not survive backup/restore.
  • GET ?versionId is ignored on read (unsupported) — even on A there is no
    way to fetch an old version's bytes over the wire.
  • Per-bucket default-encryption config is DROPPED. B's bucket has no default
    encryption after restore (404), and because the writer keys off that
    now-missing config, the restored blob is written PLAINTEXT on B — the
    at-rest-encryption property is lost even though the bytes survive.
  • Bucket lifecycle, CORS, and policy are DROPPED (all 404 on B). The manifest
    never captures them, though they live on the same bucket row.

Incidental pre-existing bug (NOT a backup defect), pinned by its own test:
S3 HEAD never emits x-amz-meta-* response headers, even for a freshly-written
object — the metadata IS stored (DB) and IS returned by the admin metadata
endpoint. Reproduces on both A and B, so it is a property of the S3 HEAD response
path, not of restore. User-metadata fidelity is therefore asserted through the
admin endpoint, and the HEAD omission has a clearly-labelled caveat test so a
future fix trips it.

Verification

  • npx nx build openbucket-backend
  • New spec: 14/14 pass, run with no flakes; no leftover listeners on
    9280/9281 after teardown.
  • Full e2e suite: 38 suites passed (1 pre-existing skip), 189 tests, no
    regressions.
  • nx lint openbucket-backend-e2e: 0 errors for the new file.

🤖 Generated with Claude Code

Adds `backup-restore-fidelity.e2e-spec.ts`: the data-safety proof for 1.0.
Unlike the existing backup-restore spec (restores WITHIN one instance, checks
only keys + bytes), this drill populates instance A with rich state, takes a
whole-instance backup, spawns a FRESH instance B (new DATA_DIR, fresh
migrations, a DIFFERENT generated SSE key, same root creds/admin), restores
into B, and asserts rich fidelity — documenting every dimension that does NOT
survive as an explicit assertion rather than faking a pass.

Survives: current object bytes (byte-exact), Content-Type, user-metadata
(persistence layer), object tags, bucket versioning status, at-rest SSE
round-trip across different instance keys (backup stores decrypted bytes).

Gaps asserted (candidate 1.0 data-loss surfaces): prior object versions
(only the current pointer row is backed up), per-bucket default-encryption
config (restored object is stored PLAINTEXT on B), lifecycle, CORS, policy.

Also pins a pre-existing, unrelated S3 read-path bug found while writing this:
HEAD never emits x-amz-meta-* headers (metadata is stored + returned by the
admin metadata endpoint). User-metadata fidelity is therefore asserted via the
admin endpoint, and the HEAD omission has its own clearly-labelled caveat test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ProjectBay
ProjectBay merged commit f01984a into main Jul 10, 2026
6 checks passed
@ProjectBay
ProjectBay deleted the test/backup-restore-fidelity-drill branch July 10, 2026 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant