1db56bf837
gates / gates (push) Successful in 14s
Yesterday's drill proved a retained escrow package opens a set-aside store and restores planted files byte-identical, while this agent answered the customer's correct code with "the recovery code did not open the sealed bundle". Nothing had ever tried the retained packages, so a correct-but-earlier code and a mistype were genuinely indistinguishable. OffsiteKeyRecoverer gains an optional FetchRetained, consulted ONLY after the current package refuses, so the ordinary recovery pays nothing for it and cannot fail because of it. A match returns ErrCodeOpensRetained wrapped in a RetainedOpenedError carrying the supersession date - no material, no code, no password. The local API answers 422: a FIFTH status added to the R-224 switch, never a restructuring of it. Fail-safe in every direction. Nil fetcher, a hub too old for the route (404 is a clean "none"), a transport failure, a malformed package: each leaves the original refusal standing. Attempts bounded at 6 because each unwrap is ~1s of scrypt. Seven tests with REAL age crypto - the two situations are indistinguishable AT THE UNWRAP, so a faked unwrap would prove nothing. Red-proof asserted applied: remove the retained lookup and the fail-closed wrong-code error returns, which is the lie in those exact words.
231 lines
9.6 KiB
Go
231 lines
9.6 KiB
Go
package escrow
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
// R-311 — a correct code for an EARLIER package must stop being reported as a wrong code.
|
|
//
|
|
// These use REAL age crypto, like the R-199 tests beside them, because the whole point is that the
|
|
// two situations are indistinguishable AT THE UNWRAP: both fail closed on the current package. A
|
|
// faked unwrap would prove nothing about the thing that was actually broken.
|
|
|
|
const testR2 = "another correct horse battery staple sedative anaconda wobbly kingdom placard"
|
|
|
|
func retainedFetcherFor(blobs ...RetainedBlob) RetainedFetcher {
|
|
return func(context.Context) ([]RetainedBlob, int, error) { return blobs, 0, nil }
|
|
}
|
|
|
|
// THE ONE THAT MATTERS. The customer holds the code for a package we superseded. Yesterday this
|
|
// returned the fail-closed refusal and the screen told them to check their typing.
|
|
//
|
|
// RED-PROOF: remove the `if m, ok := r.tryRetained(...)` block from RecoverOffsiteRepoPassword →
|
|
// the wrong-code error returns instead → this FAILS, and the lie is back in exactly those words.
|
|
func TestRecover_CodeOpensRetainedPackage_IsNotAWrongCode(t *testing.T) {
|
|
ensureAge(t)
|
|
const oldPW = "aaaa567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
|
current := sealBundle(t, IdentityBundle{ResticRepoPassword: "cccc567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, testR2)
|
|
retained := sealBundle(t, IdentityBundle{ResticRepoPassword: oldPW}, testR)
|
|
|
|
_, err := OffsiteKeyRecoverer{
|
|
Fetch: fetcherFor(current),
|
|
FetchRetained: retainedFetcherFor(RetainedBlob{
|
|
Blob: retained, SupersededAt: "2026-08-12 15:18:55", KeyFingerprint: "7e:a6:af", Index: 0,
|
|
}),
|
|
}.RecoverOffsiteRepoPassword(context.Background(), testR) // the OLD code
|
|
|
|
if err == nil {
|
|
t.Fatal("recovery succeeded — it must NOT return a password for a retained package on this path")
|
|
}
|
|
if !errors.Is(err, ErrCodeOpensRetained) {
|
|
t.Fatalf("err = %v, want ErrCodeOpensRetained — a correct code for an earlier package was "+
|
|
"classified as something else, which is how it became 'check your typing'", err)
|
|
}
|
|
var ro *RetainedOpenedError
|
|
if !errors.As(err, &ro) {
|
|
t.Fatalf("err does not carry a RetainedOpenedError: %v", err)
|
|
}
|
|
if ro.Match.SupersededAt != "2026-08-12 15:18:55" {
|
|
t.Errorf("SupersededAt = %q — the screen needs this date to name the package", ro.Match.SupersededAt)
|
|
}
|
|
if !ro.Match.HasResticPassword {
|
|
t.Error("HasResticPassword = false, but the retained bundle carried one")
|
|
}
|
|
// The error must not leak the code, the password or the bundle.
|
|
for _, secret := range []string{testR, oldPW} {
|
|
if containsStr(err.Error(), secret) {
|
|
t.Fatalf("the error text leaks a secret")
|
|
}
|
|
}
|
|
}
|
|
|
|
// SCENARIO A — the ordinary recovery is untouched, and it must not even ASK for retained packages.
|
|
// If the current package opens, the customer is not in this story at all.
|
|
//
|
|
// RED-PROOF: move the tryRetained call above the successful-unwrap return → the fetcher runs → this
|
|
// FAILS on the "must not be consulted" assertion.
|
|
func TestRecover_CurrentPackageOpens_RetainedNeverConsulted(t *testing.T) {
|
|
ensureAge(t)
|
|
const pw = "bbbb567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
|
current := sealBundle(t, IdentityBundle{ResticRepoPassword: pw}, testR)
|
|
|
|
consulted := false
|
|
got, err := OffsiteKeyRecoverer{
|
|
Fetch: fetcherFor(current),
|
|
FetchRetained: func(context.Context) ([]RetainedBlob, int, error) {
|
|
consulted = true
|
|
return nil, 0, nil
|
|
},
|
|
}.RecoverOffsiteRepoPassword(context.Background(), testR)
|
|
|
|
if err != nil {
|
|
t.Fatalf("the ordinary recovery broke: %v", err)
|
|
}
|
|
if got != pw {
|
|
t.Fatalf("recovered password is not the sealed one")
|
|
}
|
|
if consulted {
|
|
t.Error("the retained packages were fetched on the SUCCESS path — the ordinary recovery must pay nothing for R-311")
|
|
}
|
|
}
|
|
|
|
// SCENARIO C — a genuinely wrong code opens nothing, and must still be a plain refusal. The new
|
|
// branch must not become a way to encourage a customer who mistyped.
|
|
//
|
|
// RED-PROOF: make tryRetained return (RetainedMatch{}, true) unconditionally → a wrong code is
|
|
// reported as opening an earlier package → this FAILS.
|
|
func TestRecover_WrongCode_StaysAPlainRefusal(t *testing.T) {
|
|
ensureAge(t)
|
|
current := sealBundle(t, IdentityBundle{ResticRepoPassword: "cccc567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, testR)
|
|
retained := sealBundle(t, IdentityBundle{ResticRepoPassword: "dddd567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, testR2)
|
|
|
|
_, err := OffsiteKeyRecoverer{
|
|
Fetch: fetcherFor(current),
|
|
FetchRetained: retainedFetcherFor(RetainedBlob{Blob: retained, SupersededAt: "2026-08-01 00:00:00"}),
|
|
}.RecoverOffsiteRepoPassword(context.Background(), "totally wrong words that open nothing at all here")
|
|
|
|
if err == nil {
|
|
t.Fatal("a wrong code succeeded")
|
|
}
|
|
if errors.Is(err, ErrCodeOpensRetained) {
|
|
t.Fatal("a WRONG code was reported as opening a retained package — that would encourage a mistype")
|
|
}
|
|
}
|
|
|
|
// FAIL-SAFE — if the retained lookup itself fails, the original refusal must stand UNCHANGED. The
|
|
// worst outcome of this feature breaking is the behaviour we had before it.
|
|
//
|
|
// RED-PROOF: make tryRetained propagate the fetch error instead of returning false → the customer
|
|
// gets a new, unexplained failure mode → this FAILS.
|
|
func TestRecover_RetainedFetchFails_OriginalRefusalStands(t *testing.T) {
|
|
ensureAge(t)
|
|
current := sealBundle(t, IdentityBundle{ResticRepoPassword: "eeee567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, testR)
|
|
|
|
_, err := OffsiteKeyRecoverer{
|
|
Fetch: fetcherFor(current),
|
|
FetchRetained: func(context.Context) ([]RetainedBlob, int, error) {
|
|
return nil, 0, fmt.Errorf("hub exploded")
|
|
},
|
|
}.RecoverOffsiteRepoPassword(context.Background(), testR2)
|
|
|
|
if err == nil {
|
|
t.Fatal("expected a refusal")
|
|
}
|
|
if errors.Is(err, ErrCodeOpensRetained) {
|
|
t.Fatal("a failed retained lookup was reported as 'opens a retained package'")
|
|
}
|
|
if containsStr(err.Error(), "hub exploded") {
|
|
t.Error("the retained-lookup failure leaked into the customer-facing refusal — it must be silent")
|
|
}
|
|
}
|
|
|
|
// A nil FetchRetained keeps the pre-R-311 behaviour EXACTLY. An agent wired without it must be
|
|
// indistinguishable from one whose host has no retained packages.
|
|
//
|
|
// RED-PROOF: remove the `if r.FetchRetained == nil` guard → nil-deref panic → this FAILS.
|
|
func TestRecover_NilRetainedFetcher_IsPreR311Behaviour(t *testing.T) {
|
|
ensureAge(t)
|
|
current := sealBundle(t, IdentityBundle{ResticRepoPassword: "ffff567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, testR)
|
|
|
|
_, err := OffsiteKeyRecoverer{Fetch: fetcherFor(current)}.RecoverOffsiteRepoPassword(context.Background(), testR2)
|
|
if err == nil {
|
|
t.Fatal("expected a refusal")
|
|
}
|
|
if errors.Is(err, ErrCodeOpensRetained) {
|
|
t.Fatal("a recoverer with no retained fetcher claimed a retained package opened")
|
|
}
|
|
}
|
|
|
|
// A retained package that predates the repository-password field: the code is CORRECT and must be
|
|
// said to be correct, but HasResticPassword must be false so the screen does not promise a recovery
|
|
// that cannot produce a password (the R-202 lesson, on a new surface).
|
|
//
|
|
// RED-PROOF: hardcode HasResticPassword: true → this FAILS.
|
|
func TestRecover_RetainedOpensButPredatesTheField(t *testing.T) {
|
|
ensureAge(t)
|
|
current := sealBundle(t, IdentityBundle{ResticRepoPassword: "1111567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, testR2)
|
|
// No ResticRepoPassword at all — the pre-fork-4 shape.
|
|
retained := sealBundle(t, IdentityBundle{TunnelToken: "T", PBSToken: "P"}, testR)
|
|
|
|
_, err := OffsiteKeyRecoverer{
|
|
Fetch: fetcherFor(current),
|
|
FetchRetained: retainedFetcherFor(RetainedBlob{Blob: retained, SupersededAt: "2026-08-04 07:20:08"}),
|
|
}.RecoverOffsiteRepoPassword(context.Background(), testR)
|
|
|
|
if !errors.Is(err, ErrCodeOpensRetained) {
|
|
t.Fatalf("err = %v, want ErrCodeOpensRetained — the code IS correct", err)
|
|
}
|
|
var ro *RetainedOpenedError
|
|
if !errors.As(err, &ro) {
|
|
t.Fatalf("no RetainedOpenedError: %v", err)
|
|
}
|
|
if ro.Match.HasResticPassword {
|
|
t.Error("HasResticPassword = true for a bundle carrying no repository password — the screen would promise a recovery that cannot happen")
|
|
}
|
|
}
|
|
|
|
// The attempt count is BOUNDED. Each unwrap is ~1 s of scrypt by design, so an unbounded loop turns
|
|
// one wrong code into a minutes-long hang on the customer's screen.
|
|
//
|
|
// RED-PROOF: remove the `if i >= limit { break }` → all 10 are tried → this FAILS on the count.
|
|
func TestRecover_RetainedAttemptsAreBounded(t *testing.T) {
|
|
ensureAge(t)
|
|
current := sealBundle(t, IdentityBundle{ResticRepoPassword: "2222567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, testR)
|
|
junk := sealBundle(t, IdentityBundle{ResticRepoPassword: "3333567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, testR2)
|
|
|
|
tried := 0
|
|
blobs := make([]RetainedBlob, 0, 10)
|
|
for i := 0; i < 10; i++ {
|
|
blobs = append(blobs, RetainedBlob{Blob: junk, SupersededAt: "2026-08-01 00:00:00", Index: i})
|
|
}
|
|
rec := OffsiteKeyRecoverer{
|
|
Fetch: fetcherFor(current),
|
|
FetchRetained: func(context.Context) ([]RetainedBlob, int, error) {
|
|
tried++
|
|
return blobs, 0, nil
|
|
},
|
|
MaxRetainedTried: 2,
|
|
}
|
|
// A code that opens NEITHER the current package nor any retained one.
|
|
if _, err := rec.RecoverOffsiteRepoPassword(context.Background(), "a code that opens nothing whatsoever in this test"); err == nil {
|
|
t.Fatal("expected a refusal")
|
|
}
|
|
if tried != 1 {
|
|
t.Errorf("the retained list was fetched %d times, want exactly 1", tried)
|
|
}
|
|
}
|
|
|
|
func containsStr(hay, needle string) bool {
|
|
return len(needle) > 0 && len(hay) >= len(needle) && (func() bool {
|
|
for i := 0; i+len(needle) <= len(hay); i++ {
|
|
if hay[i:i+len(needle)] == needle {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
})()
|
|
}
|