R-304: the recovery screen says 'we do not know' when earlier packages were not checked (hu + en)
gates / gates (push) Successful in 54s
gates / gates (push) Successful in 54s
Unreleased; ships with tomorrow's release. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -446,6 +446,17 @@ func (s *Server) recoveryUnlockHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.logger.Printf("[INFO] [web] recovery: the code opened a RETAINED package — the customer is not at fault")
|
||||
s.renderRecovery(w, r, "A kódod helyes, de egy korábbi csomagot nyit meg, nem azt, amit most őrzünk ehhez a géphez. A géped időközben új mentési kulcsot kapott. A korábbi csomagot"+when+" nem töröltük, megőrizzük — a mostani mentéseidet ez nem érinti, azokkal semmi nem történt. A régebbi előzményed visszanyitásához a Felhom ügyfélszolgálatának segítsége kell: írj nekik, és add meg, hogy a régi mentéseidhez szeretnél hozzáférni. A kódodat tedd el, szükség lesz rá.", "", nil)
|
||||
return
|
||||
case agentapi.RecoveryOlderUnchecked:
|
||||
// ── R-304 (2026-10-08) — NOT EVERY EARLIER PACKAGE WAS TRIED. ────────────────────────────
|
||||
//
|
||||
// The current package refused the code and no earlier package opened it, but the hub holds
|
||||
// earlier packages the agent could not try (no key material, over a cap, unreadable list). So we
|
||||
// do NOT know the code is wrong, and the message says exactly that, names the mistype as one
|
||||
// possibility (R-226: a new-code holder may be typing), and names the route. Pinned by
|
||||
// TestR304_OlderUnchecked_IsNotAWrongCode.
|
||||
s.logger.Printf("[WARN] [web] recovery: earlier sealed packages were not all checked — not reported as a wrong code (R-304)")
|
||||
s.renderRecovery(w, r, s.msg(r, "recovery.older_unchecked"), "", nil)
|
||||
return
|
||||
case agentapi.RecoveryAskedAndRefused:
|
||||
// The bundle was fetched and the code did not open it. THIS is the only class from which
|
||||
// the customer may be told to check their typing — see the two messages below.
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/agentapi"
|
||||
)
|
||||
|
||||
// ── R-304 (2026-10-08) — NOT EVERY EARLIER PACKAGE WAS CHECKED, SO THE CODE IS NOT CALLED WRONG ───
|
||||
//
|
||||
// The agent answers 424 when the current package refused the code, no earlier package opened it, and some
|
||||
// earlier package the hub holds was never tried. The page must not accuse („nem fogadtuk el"), must say that
|
||||
// we do not know whether the code is wrong, and must name the route — in both languages.
|
||||
//
|
||||
// RED-PROOF: delete the `agentapi.RecoveryOlderUnchecked` case from recoveryUnlockHandler → the 424 falls into
|
||||
// the safe default („nem tudjuk biztosan, miért") → this FAILS on the „do not know whether wrong" sentence.
|
||||
func TestR304_OlderUnchecked_IsNotAWrongCode(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
lang, mustSay, route, mustNotSay string
|
||||
}{
|
||||
{"hu", "nem tudjuk, hogy a kódod hibás-e", "ügyfélszolgálat", "nem fogadtuk el"},
|
||||
{"en", "we do not know whether your code is wrong", "contact Felhom support", "nem tudjuk"},
|
||||
} {
|
||||
t.Run(tc.lang, func(t *testing.T) {
|
||||
f := newRecoveryFixture(t)
|
||||
f.rec.failWith = refusal(http.StatusFailedDependency, "the recovery code did not open the current sealed package, and earlier packages the hub holds were not all checked")
|
||||
form := url.Values{"recovery_code": {testRecoveryCode}}
|
||||
req := httptest.NewRequest(http.MethodPost, "/recovery/unlock", strings.NewReader(form.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.AddCookie(&http.Cookie{Name: langCookieName, Value: tc.lang})
|
||||
rr := httptest.NewRecorder()
|
||||
f.s.recoveryUnlockHandler(rr, req)
|
||||
body := rr.Body.String()
|
||||
if !strings.Contains(body, tc.mustSay) {
|
||||
t.Fatalf("[%s] the page must say we do not know whether the code is wrong; got %q", tc.lang, firstAlert(body))
|
||||
}
|
||||
if !strings.Contains(body, tc.route) {
|
||||
t.Errorf("[%s] the page must name the route (support); got %q", tc.lang, firstAlert(body))
|
||||
}
|
||||
if strings.Contains(body, tc.mustNotSay) {
|
||||
t.Errorf("[%s] the page must not say %q; got %q", tc.lang, tc.mustNotSay, firstAlert(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// The classifier maps 424 to its own class, never to the accusing one, with or without the version gates.
|
||||
func TestR304_Classify424(t *testing.T) {
|
||||
err := refusal(http.StatusFailedDependency, "x")
|
||||
for _, trust := range []bool{false, true} {
|
||||
if got := agentapi.ClassifyRecoveryFailure(err, trust, trust); got != agentapi.RecoveryOlderUnchecked {
|
||||
t.Fatalf("trust=%v: 424 classified %s, want older-unchecked", trust, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user