| 1 | //go:build linux |
| 2 | |
| 3 | package hostfiles |
| 4 | |
| 5 | import ( |
| 6 | "context" |
| 7 | "errors" |
| 8 | "os" |
| 9 | "path/filepath" |
| 10 | "strings" |
| 11 | "testing" |
| 12 | "time" |
| 13 | |
| 14 | "github.com/carlosframework/platform/internal/release" |
| 15 | ) |
| 16 | |
| 17 | // Fix 4 (Astra confirming P2): a deep path within the byte cap (257 |
| 18 | // one-byte components, 513 bytes) travels the whole way: published by a |
| 19 | // walk, accepted by every reader, restored and found present. |
| 20 | func TestADeepPathWithinTheCapPublishesAndRestores(t *testing.T) { |
| 21 | ctx := context.Background() |
| 22 | rel := strings.Repeat("d/", 256) + "f" |
| 23 | src := t.TempDir() |
| 24 | root, err := os.OpenRoot(src) |
| 25 | if err != nil { |
| 26 | t.Fatal(err) |
| 27 | } |
| 28 | if err := root.MkdirAll(strings.TrimSuffix(strings.Repeat("d/", 256), "/"), 0o700); err != nil { |
| 29 | t.Fatal(err) |
| 30 | } |
| 31 | if err := root.WriteFile(rel, []byte("deep"), 0o600); err != nil { |
| 32 | t.Fatal(err) |
| 33 | } |
| 34 | root.Close() |
| 35 | s := release.NewDirStore(t.TempDir()) |
| 36 | p := open(t, s) |
| 37 | if _, err := SyncDir(ctx, p, src, nil); err != nil { |
| 38 | t.Fatal(err) |
| 39 | } |
| 40 | commit(t, p) |
| 41 | m, _, err := Load(ctx, s, pfx) |
| 42 | if err != nil { |
| 43 | t.Fatal(err) |
| 44 | } |
| 45 | if err := ValidateManifest(m, []string{pfx}); err != nil { |
| 46 | t.Fatalf("ValidateManifest refused what the writer published: %v", err) |
| 47 | } |
| 48 | dst := t.TempDir() |
| 49 | if _, st, err := Restore(ctx, s, pfx, dst, nil); err != nil || st.Written != 1 { |
| 50 | t.Fatalf("Restore: %+v %v", st, err) |
| 51 | } |
| 52 | r2, err := os.OpenRoot(dst) |
| 53 | if err != nil { |
| 54 | t.Fatal(err) |
| 55 | } |
| 56 | defer r2.Close() |
| 57 | if b, err := r2.ReadFile(rel); err != nil || string(b) != "deep" { |
| 58 | t.Fatalf("restored %q %v", b, err) |
| 59 | } |
| 60 | if ok, err := Present(dst, filepath.Join(t.TempDir(), "shop.example.env"), m, true); err != nil || !ok { |
| 61 | t.Fatalf("Present: %v %v", ok, err) |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | // Every writer refuses a path past the byte cap, exactly where the readers |
| 66 | // do, and accepts one at it; Commit never writes a manifest that holds one. |
| 67 | func TestTheWritersRefuseAPathPastTheCapAsTheReadersDo(t *testing.T) { |
| 68 | ctx := context.Background() |
| 69 | at, past := pathOfBytes(MaxPathBytes), pathOfBytes(MaxPathBytes+1) |
| 70 | p := open(t, release.NewDirStore(t.TempDir())) |
| 71 | if err := p.Stage(ctx, at, []byte("x"), 0o600, false); err != nil { |
| 72 | t.Fatalf("Stage at the cap: %v", err) |
| 73 | } |
| 74 | if err := p.Stage(ctx, past, []byte("x"), 0o600, false); !errors.Is(err, ErrTooDeep) { |
| 75 | t.Fatalf("Stage past the cap: %v", err) |
| 76 | } |
| 77 | if err := p.StageSkipped(past, "too-large"); !errors.Is(err, ErrTooDeep) { |
| 78 | t.Fatalf("StageSkipped past the cap: %v", err) |
| 79 | } |
| 80 | if err := p.StageDelete(past); !errors.Is(err, ErrTooDeep) { |
| 81 | t.Fatalf("StageDelete past the cap: %v", err) |
| 82 | } |
| 83 | // A manifest the publisher continued that already holds such a path |
| 84 | // (written before the cap) is refused at Commit, never written again. |
| 85 | s := release.NewDirStore(t.TempDir()) |
| 86 | q := open(t, s) |
| 87 | q.mu.Lock() |
| 88 | q.next++ |
| 89 | q.man.Entries[past], q.dirty = Entry{Seq: q.next, Skipped: "too-large"}, true |
| 90 | q.mu.Unlock() |
| 91 | if _, err := q.Commit(ctx); !errors.Is(err, ErrTooDeep) { |
| 92 | t.Fatalf("Commit of a manifest holding a path past the cap: %v", err) |
| 93 | } |
| 94 | if _, found, err := Load(ctx, s, pfx); found || err != nil { |
| 95 | t.Fatalf("a refused Commit wrote a manifest: %v %v", found, err) |
| 96 | } |
| 97 | // And the readers draw the line at the same byte. |
| 98 | sha := strings.Repeat("a", 64) |
| 99 | e := Entry{Object: pfx + objectKey(1, sha), SHA256: sha, Seq: 1, Size: 1} |
| 100 | for path, ok := range map[string]bool{at: true, past: false} { |
| 101 | err := ValidateManifest(Manifest{V: ManifestVersion, Seq: 1, Entries: map[string]Entry{path: e}, Platform: map[string]Entry{}}, []string{pfx}) |
| 102 | if ok != (err == nil) || !ok && !errors.Is(err, ErrTooDeep) { |
| 103 | t.Fatalf("ValidateManifest of %d bytes: %v", len(path), err) |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | // The watcher skips a path past the cap for good: it is never staged, so |
| 109 | // no manifest a reader refuses is committed; it is not retried; and it |
| 110 | // costs one log line however often it is touched. Other paths publish. |
| 111 | func TestRunSkipsAPathPastTheCapAndLogsItOnce(t *testing.T) { |
| 112 | logs := captureLog(t) |
| 113 | s, dir, w := release.NewDirStore(t.TempDir()), t.TempDir(), newFake() |
| 114 | p := open(t, s) |
| 115 | stop := startRun(t, p, dir, w, eventsOnly) |
| 116 | past := pathOfBytes(MaxPathBytes + 1) |
| 117 | root, err := os.OpenRoot(dir) |
| 118 | if err != nil { |
| 119 | t.Fatal(err) |
| 120 | } |
| 121 | if err := root.MkdirAll(filepath.Dir(past), 0o700); err != nil { |
| 122 | t.Fatal(err) |
| 123 | } |
| 124 | if err := root.WriteFile(past, []byte("x"), 0o600); err != nil { |
| 125 | t.Fatal(err) |
| 126 | } |
| 127 | root.Close() |
| 128 | w.ch <- event{rel: past} |
| 129 | write(t, dir, "ok", "ok") |
| 130 | w.ch <- event{rel: "ok"} |
| 131 | eventually(t, "ok published", func() bool { return manifestHas(s, "ok", sum([]byte("ok"))) }) |
| 132 | w.ch <- event{rel: past} |
| 133 | w.ch <- event{rel: "ok"} |
| 134 | eventually(t, "the second touch handled", func() bool { return logs.count("past the 4095-byte cap") >= 1 }) |
| 135 | // Long enough for a retry at every deadline to have logged again. |
| 136 | time.Sleep(10 * eventsOnly.Deadline) |
| 137 | stopErr := stop() |
| 138 | if !errors.Is(stopErr, context.Canceled) { |
| 139 | t.Fatalf("run ended with %v; a path past the cap must be skipped, not fatal", stopErr) |
| 140 | } |
| 141 | if got := logs.count("past the 4095-byte cap"); got != 1 { |
| 142 | t.Fatalf("logged %d times, want once", got) |
| 143 | } |
| 144 | m, _, err := Load(context.Background(), s, pfx) |
| 145 | if err != nil { |
| 146 | t.Fatal(err) |
| 147 | } |
| 148 | if _, ok := m.Entries[past]; ok { |
| 149 | t.Fatal("the watcher published a path past the cap") |
| 150 | } |
| 151 | if err := ValidateManifest(m, []string{pfx}); err != nil { |
| 152 | t.Fatalf("the watcher committed a manifest a reader refuses: %v", err) |
| 153 | } |
| 154 | } |
| 155 | |