Files
felhom.eu/hub/internal/offsite/scanner_ipv4_test.go
T
admin 655f5f66f8
gates / gates (push) Successful in 6m0s
hub v0.147.0 (code): the operator's answers S4, S6, S10, S29, S30, S32, S33
- S4 / R-242: GoldenVouchChecker - a published golden unvouched for 2 h raises golden_not_vouched (operator only)
- S6 / R-244: the delete cascade de-references app_log_issues; one-time sweep flag -sweep-app-log-residue=count|apply
- S10 / R-266: read_failed storage entry shows "read failed", not 0 %
- S29 / R-250: host-key scan IPv4 first, ~2 min ladder, "safe to press Save again" error
- S30 / R-246: stale_at retired (reader, setter, badge)
- S32 / R-521: storage_reconnected ends the storage_disconnected cooldown on both channels
- S33 / R-402: host page "Last full check (off-site)" line; two wire-gate allowlist entries removed
Each with a test seen failing first. Not built or deployed yet (operator-attended deploy).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-12 14:54:14 +02:00

49 lines
2.1 KiB
Go

package offsite
import (
"context"
"errors"
"net"
"strings"
"testing"
)
// R-250 (operator ruling 2026-10-12, S29, `09` §3 decision 224): a fresh Storage Box name resolves
// AAAA-first, and the hub pod has no IPv6 route — measured 2026-08-07: `dial tcp [2a01:…]:23: connect:
// network is unreachable` while the A record already worked. The scan dials IPv4 FIRST and falls back to
// any family only when IPv4 fails.
// RED-PROOF: with the old single `DialContext(ctx, "tcp", …)` the first network recorded is "tcp".
func TestScannerDialsIPv4First(t *testing.T) {
var nets []string
s := SSHHostKeyScanner{dial: func(_ context.Context, network, _ string) (net.Conn, error) {
nets = append(nets, network)
return nil, errors.New("refused in test")
}}
if _, err := s.Fingerprint(context.Background(), "box.example", 23); err == nil {
t.Fatal("a failed dial must fail the scan")
}
if len(nets) != 2 || nets[0] != "tcp4" || nets[1] != "tcp" {
t.Fatalf("dial order = %v, want [tcp4 tcp]", nets)
}
}
// R-250 second half: when the scan runs out, the operator is told it is safe to press again, and a
// second press really creates nothing twice. RED-PROOF: with the old wrap ("offsite: host-key scan …")
// errors.Is fails and the text has no „SAFE to press".
func TestScanOutOfRetriesSaysSafeToPressAgain(t *testing.T) {
p, fake, _ := newTestProvisioner(t)
p.Scanner = &fakeScanner{err: errors.New("dial tcp: lookup box: no such host")}
_, err := p.ProvisionOffsite(context.Background(), "cust-r250", Input{Enabled: true, Type: "shared", QuotaGB: 10})
if !errors.Is(err, ErrScanNotYetReachable) || !strings.Contains(err.Error(), "SAFE to press Save again") {
t.Fatalf("err = %v, want the safe-to-press-again error", err)
}
n := len(fake.Subaccounts)
p.Scanner = &fakeScanner{fp: "SHA256:ok"}
if _, err := p.ProvisionOffsite(context.Background(), "cust-r250", Input{Enabled: true, Type: "shared", QuotaGB: 10}); err != nil {
t.Fatalf("second press: %v", err)
}
if len(fake.Subaccounts) != n {
t.Fatalf("the second press created another sub-account (%d → %d)", n, len(fake.Subaccounts))
}
}