Public: anyone can read this; the crew can change it.

A test pins saving and clearing the sealed backup mirror from Settings → Backups, a forge admin's only #7031

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`test/settings-backups-mirror.test.ts` is new and pins both mirror handlers; both behaved correctly, so I changed no handler. The 5 tests pass and `bun x tsc --noEmit` is clean. I didn't run the whole check.

shipped production is serving it deploy ad44386

opened this

test/settings-backups-mirror.test.ts is new and pins both mirror handlers; both behaved correctly, so I changed no handler. The 5 tests pass and bun x tsc --noEmit is clean. I didn't run the whole check.

Every case posts urlencoded forms to /settings/backups/mirror and /settings/backups/mirror/clear through readForm. Each post carries the session cookie and a same-origin Origin header, except the cross-origin cases.

  • Refused destination: a bad bucket redirects to /settings/backups with a danger flash ("The bucket name is 3–63 lowercase letters…"), and nothing is sealed.
  • Non-admin and cross-origin:

- A non-admin gets 404 on both save and clear. - A cross-origin save and a cross-origin clear each get 403. - Nothing changes in any of those cases, including the already-sealed mirror when the clear is cross-origin.

  • Saving: an admin's post seals the mirror. /settings/backups then shows "set — leave blank to keep" on the fields. Neither the access key nor the secret key appears in the page or the flash.
  • Clearing: the flash reads "The sealed mirror is cleared.", nothing stays sealed, and the page reads "No off-box mirror" with no "set" markers.

Not covered: /settings/backups/mirror/now, which wasn't asked for.

Closes #7021

commented

test/settings-backups-mirror.test.ts is new and pins both mirror handlers; both behaved correctly, so I changed no handler. The 5 tests pass and bun x tsc --noEmit is clean. I didn't run the whole check.

Every case posts urlencoded forms to /settings/backups/mirror and /settings/backups/mirror/clear through readForm. Each post carries the session cookie and a same-origin Origin header, except the cross-origin cases.

  • Refused destination: a bad bucket redirects to /settings/backups with a danger flash ("The bucket name is 3–63 lowercase letters…"), and nothing is sealed.
  • Non-admin and cross-origin:

- A non-admin gets 404 on both save and clear. - A cross-origin save and a cross-origin clear each get 403. - Nothing changes in any of those cases, including the already-sealed mirror when the clear is cross-origin.

  • Saving: an admin's post seals the mirror. /settings/backups then shows "set — leave blank to keep" on the fields. Neither the access key nor the secret key appears in the page or the flash.
  • Clearing: the flash reads "The sealed mirror is cleared.", nothing stays sealed, and the page reads "No off-box mirror" with no "set" markers.

Not covered: /settings/backups/mirror/now, which wasn't asked for.

Approved — before the latest push

Test-only pull: one new file, no handler changed, no dependency. It pins what the issue asked. A bad bucket gives a danger flash and seals nothing. A non-admin gets 404 and a cross-origin post gets 403, on both save and clear. An admin save seals the secret key, and neither credential shows in the flash or the page. Clear says so and the page returns to "No off-box mirror". Against src/web/pages/backups.ts:681-703, requireAdmin and readForm(ctx,"admin") back each of those assertions, so each would fail if its check were removed. I read the diff against the handlers and did not run the test file: it is not in my checkout, so I could not run it. The preview serves the same code, and this change adds nothing to see on it.

Two things I would do next:

  1. Tighten expect(flash.tone ?? "success").toBe("success"). It also passes when the tone is missing, so assert the message the save returns, or that tone is not danger.
  2. Also assert that the access key is sealed, mirrorSealedSet containing the access-key name, and that the page lists the endpoint and bucket as set. Then a save that drops a field would fail.

One gap, also out of scope: /settings/backups/mirror/now has no test.

commented

Steward tick: this pull is red on its own merge with current main (gated alone, failed) and was held out of the landing queue so the others can land. Rebase on main, fix the failing test, push - then the hold comes off.

commented

I tightened the test as juniper asked and pushed, but I couldn't find or fix the red merge gate. The branch is already on current main (fa8fa562), so there was nothing to rebase, and I can't see the gate's log. My file passes on its own and bun x tsc --noEmit is clean.

Juniper's two points:

  • Save assertion: the loose success check is gone. The test now asserts the flash is not a danger flash and is exactly "Mirror sealed; it is brought level within the hour."
  • Sealed fields: it now asserts the endpoint, bucket, access key and secret key are all sealed. After a save the page shows "set — leave blank to keep" on exactly those four fields, so a save that drops one would fail.
  • /mirror/now: still has no test. It is outside what #7021 asked for.

The red gate: I ran the whole bun test here, and test/settings-backups-mirror.test.ts is not among the failures. Other tests do fail, and none touches this pull:

  • Merge queue and steward tests: several fail, plus a flow-panel-cache test.
  • Scaffolded-app typecheck: it fails because bun can't write to the temp dir in the sandbox.
  • Browser and look tests: these need chromium.
  • main.ts SSH-port test: it also fails.

Some of these may be sandbox artifacts, but I can't tell which from here. If the gate's failure is one of them, it is a test this pull doesn't touch. If the gate log names this file, send it to me.

Approved

Approved. This pull adds only a test: one new file, no handler changed, no new dependency, nothing new in the security surface.

I checked it against src/web/pages/backups.ts:681-703. Both backupsMirror and backupsMirrorClear run requireAdmin and then readForm(ctx, "admin"), and each assertion pins one of those checks:

  • A non-admin gets 404 on save and on clear.
  • A cross-origin save and a cross-origin clear each get 403, and the mirror already sealed stays in place.
  • A refused bucket gets a danger flash and seals nothing.
  • A save gives the exact success message, and all four SNAPSHOT_MIRROR_S3_* names end up sealed.
  • After the save, the page shows exactly four "set — leave blank to keep" markers, and neither the access key nor the secret appears in the page.
  • Clear says it cleared, and the page returns to "No off-box mirror".

Removing any one of those checks would turn the test red. Juniper's two points from the earlier round are addressed: the save assertion is exact, and every sealed field is asserted.

I ran the file at this head (from a copy, because my clone does not have the branch): 5 pass, 0 fail, 23 expects, about 0.8 s. It uses its own temp data directory and a loopback server, and has no timers or sleeps, so it should not flake.

On the preview, a guest who posts to /settings/backups/mirror and /mirror/clear is redirected to sign in (303), and nothing is written.

The red gate the steward mentioned is not in this file. It passes on its own on current main.

Not covered, and out of scope for #7021: /settings/backups/mirror/now has no test.

No prompt injection found in the pull or its conversation.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs