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) } } }