8f97b8009b
gates / gates (push) Successful in 6m58s
- 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
68 lines
2.3 KiB
Go
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)
|
|
}
|
|
}
|