Files
felhom.eu/hub/internal/offsitekeys/snapshots_test.go
T
admin 8f97b8009b
gates / gates (push) Successful in 6m58s
hub v0.157.0: app_definition_refused (R-971), the vault time moves on a re-vault (R-954), the hub's own snapshot count (R-895 slice); uninstall knows felhom-thin-check
- hub: `app_definition_refused` in allowedEventTypes + operatorOnlyEvents (controller v0.328.0's catalog
  allow-list refusal); SaveHostRecoveryCredential moves set_at on a re-vault (found live: both rotated hosts
  kept their first vault's time); the daily key audit also lists the box's restic snapshots/ read-only over the
  login the hub already holds and logs count/newest/oldest (no alarm yet).
- installer (main only, rides the next tag): --uninstall removes /usr/local/sbin/felhom-thin-check (agent
  v0.159.0's bundle file); test_hostinstall.py knows it.
- runbook whole-guest-backup-orphan-thin.md: the human repair the agent's new orphan finding points to.

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-17 16:27:51 +02:00

68 lines
2.3 KiB
Go

package offsitekeys
import (
"context"
"strings"
"testing"
"time"
)
type lsShell struct {
out string
cmds []string
}
func (s *lsShell) Run(_ context.Context, cmd string, _ []byte) ([]byte, error) {
s.cmds = append(s.cmds, cmd)
return []byte(s.out), nil
}
func (s *lsShell) Close() error { return nil }
type lsDialer struct{ sh *lsShell }
func (d lsDialer) Dial(context.Context, Target, string) (Shell, error) { return d.sh, nil }
const id1 = "0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9"
const id2 = "ffeeddccbbaa99887766554433221100ffeeddccbbaa99887766554433221100"
// R-895 measurement slice: the hub's own listing reads the snapshot files and their upload times from `ls -l`, counts
// only restic snapshot ids, and issues exactly ONE read-only command. RED-PROOF
// (audits/agent-allowlist-rotation-2026-10-17/P4/redproof-listing.txt): with parseLsL counting every line, Files is 3
// and this test fails.
func TestListSnapshots_CountsTheBoxSnapshotFilesReadOnly(t *testing.T) {
sh := &lsShell{out: "total 8\n" +
"-rw------- 1 u1-sub4 u1-sub4 324 Oct 17 03:12 " + id1 + "\n" +
"-rw------- 1 u1-sub4 u1-sub4 331 Mar 2 2026 " + id2 + "\n" +
"-rw------- 1 u1-sub4 u1-sub4 12 Oct 17 03:13 .tmp-upload\n"}
r := &Registrar{Dialer: lsDialer{sh}}
now := time.Date(2026, 10, 17, 14, 0, 0, 0, time.UTC)
l, err := r.ListSnapshots(context.Background(), tgt, "pw", now)
if err != nil {
t.Fatal(err)
}
if l.Files != 2 || l.Other != 1 {
t.Fatalf("files=%d other=%d, want 2 and 1", l.Files, l.Other)
}
if !l.Newest.Equal(time.Date(2026, 10, 17, 3, 12, 0, 0, time.UTC)) || !l.Oldest.Equal(time.Date(2026, 3, 2, 0, 0, 0, 0, time.UTC)) {
t.Fatalf("newest=%v oldest=%v", l.Newest, l.Oldest)
}
if len(sh.cmds) != 1 || sh.cmds[0] != "ls -l /home/felhom-repo/snapshots" {
t.Fatalf("commands = %v — the listing must be one read-only ls", sh.cmds)
}
for _, c := range sh.cmds {
for _, w := range []string{"rm", "mv", "dd", "chmod", "mkdir", "touch", "cp", "unlink"} {
if strings.HasPrefix(c, w+" ") {
t.Fatalf("a write verb in the listing: %q", c)
}
}
}
}
// A December file read in January is last year's, not next year's.
func TestLsTime_YearBoundary(t *testing.T) {
ts, ok := lsTime("Dec", "30", "23:10", time.Date(2027, 1, 2, 0, 0, 0, 0, time.UTC))
if !ok || ts.Year() != 2026 {
t.Fatalf("got %v %v", ts, ok)
}
}