| 1 | package release |
| 2 | |
| 3 | import ( |
| 4 | "os" |
| 5 | "path/filepath" |
| 6 | "testing" |
| 7 | "time" |
| 8 | ) |
| 9 | |
| 10 | func TestRefusalRoundTripAndBlocks(t *testing.T) { |
| 11 | dir := t.TempDir() |
| 12 | at := time.Date(2026, 10, 6, 9, 30, 30, 0, time.UTC) |
| 13 | r := Refusal{Host: "console.example.com", App: "console", Version: "v2", |
| 14 | SHA256: "abc", Platform: "linux-arm64", PointerPromotedAt: at, |
| 15 | RefusedAt: at.Add(10 * time.Second), Reason: "exited: status=2"} |
| 16 | if err := WriteRefusal(dir, r); err != nil { |
| 17 | t.Fatal(err) |
| 18 | } |
| 19 | got, err := ReadRefusal(dir, "console.example.com") |
| 20 | if err != nil || got == nil { |
| 21 | t.Fatalf("ReadRefusal = %+v, %v", got, err) |
| 22 | } |
| 23 | if got.Schema != 1 || got.Version != "v2" || !got.PointerPromotedAt.Equal(at) { |
| 24 | t.Fatalf("round trip = %+v", got) |
| 25 | } |
| 26 | if !got.Blocks(&ChannelPointer{Version: "v2", PromotedAt: at}) { |
| 27 | t.Fatal("the same promotion is not blocked") |
| 28 | } |
| 29 | if got.Blocks(&ChannelPointer{Version: "v2", PromotedAt: at.Add(time.Second)}) { |
| 30 | t.Fatal("a re-signed pointer (retry) is still blocked") |
| 31 | } |
| 32 | if got.Blocks(&ChannelPointer{Version: "v3", PromotedAt: at}) { |
| 33 | t.Fatal("a different version is blocked") |
| 34 | } |
| 35 | var nilR *Refusal |
| 36 | if nilR.Blocks(&ChannelPointer{Version: "v2", PromotedAt: at}) { |
| 37 | t.Fatal("a nil refusal blocks") |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | func TestReadRefusalAbsentIsNil(t *testing.T) { |
| 42 | got, err := ReadRefusal(t.TempDir(), "nobody.example.com") |
| 43 | if got != nil || err != nil { |
| 44 | t.Fatalf("absent = %+v, %v; want nil, nil", got, err) |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | func TestReadRefusalCorruptIsAbsent(t *testing.T) { |
| 49 | dir := t.TempDir() |
| 50 | p := filepath.Join(RefusalDir(dir), "console.example.com.json") |
| 51 | if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { |
| 52 | t.Fatal(err) |
| 53 | } |
| 54 | if err := os.WriteFile(p, []byte(`{"schema":1,"host":`), 0o644); err != nil { |
| 55 | t.Fatal(err) |
| 56 | } |
| 57 | got, err := ReadRefusal(dir, "console.example.com") |
| 58 | if got != nil || err != nil { |
| 59 | t.Fatalf("corrupt = %+v, %v; want nil, nil (a torn file must never block)", got, err) |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | func TestRefusalRejectsAPathInTheHost(t *testing.T) { |
| 64 | if err := WriteRefusal(t.TempDir(), Refusal{Host: "../etc/x"}); err == nil { |
| 65 | t.Fatal("a host with a path separator was written") |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | func TestListAndClearRefusals(t *testing.T) { |
| 70 | dir := t.TempDir() |
| 71 | for _, h := range []string{"a.example.com", "b.example.com"} { |
| 72 | if err := WriteRefusal(dir, Refusal{Host: h, Version: "v2"}); err != nil { |
| 73 | t.Fatal(err) |
| 74 | } |
| 75 | } |
| 76 | if err := ClearRefusal(dir, "a.example.com"); err != nil { |
| 77 | t.Fatal(err) |
| 78 | } |
| 79 | if err := ClearRefusal(dir, "never.example.com"); err != nil { |
| 80 | t.Fatalf("clearing an absent record: %v", err) |
| 81 | } |
| 82 | all, err := ListRefusals(dir) |
| 83 | if err != nil || len(all) != 1 || all[0].Host != "b.example.com" { |
| 84 | t.Fatalf("ListRefusals = %+v, %v", all, err) |
| 85 | } |
| 86 | } |
| 87 | |