| 1 | package host |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "encoding/json" |
| 6 | "testing" |
| 7 | |
| 8 | "github.com/carlosframework/platform/internal/lease" |
| 9 | "github.com/carlosframework/platform/internal/moves" |
| 10 | "github.com/carlosframework/platform/internal/provision" |
| 11 | ) |
| 12 | |
| 13 | // Final review finding 4: a version id of "null" (a versioning-suspended |
| 14 | // bucket) pins nothing, so a ledger that recorded one is no evidence. The |
| 15 | // next round restages the archive under real version ids and asks for |
| 16 | // move.json again, and the source report never carries "null". |
| 17 | func TestNullVersionsInTheLedgerAreRestaged(t *testing.T) { |
| 18 | ctx := context.Background() |
| 19 | h := newPhase1Harness(t) |
| 20 | h.start(t, "manual") |
| 21 | h.pass(t) |
| 22 | l := h.ledger(t) |
| 23 | if l.ArchiveVersions == nil || !l.ArchiveVersions.Pinned() { |
| 24 | t.Fatalf("the first round staged no pinned archive: %+v", l.ArchiveVersions) |
| 25 | } |
| 26 | ref := *l.ArchiveVersions |
| 27 | ref.ManifestVersion, ref.SealedVersion = "null", "null" |
| 28 | l.ArchiveVersions, l.MoveJSONVersion = &ref, "null" |
| 29 | if err := writeMoveLedger(ctx, h.f, "data-ie", moves.LedgerKey(p1Host, p1ID), l); err != nil { |
| 30 | t.Fatal(err) |
| 31 | } |
| 32 | |
| 33 | h.pass(t) |
| 34 | body, err := h.f.Get(ctx, "data-ie", moves.LedgerKey(p1Host, p1ID)) |
| 35 | if err != nil { |
| 36 | t.Fatal(err) |
| 37 | } |
| 38 | var raw moveLedger |
| 39 | if err := json.Unmarshal(body, &raw); err != nil { |
| 40 | t.Fatal(err) |
| 41 | } |
| 42 | if raw.ArchiveVersions == nil || !raw.ArchiveVersions.Pinned() { |
| 43 | t.Fatalf("the null-version archive was kept: %+v", raw.ArchiveVersions) |
| 44 | } |
| 45 | if raw.MoveJSONVersion != moveJSONPresent { |
| 46 | t.Fatalf("move_json_version = %q, want %q (asked again, found present)", raw.MoveJSONVersion, moveJSONPresent) |
| 47 | } |
| 48 | if sr := h.sourceReport(t); sr.Archive == nil || !sr.Archive.Pinned() { |
| 49 | t.Fatalf("the source report carries %+v", sr.Archive) |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | // T5 refuses an archive reference that names "null" before it looks in its |
| 54 | // cache of verdicts: a passing verdict cached for that reference would |
| 55 | // otherwise vouch for whatever the key holds now. |
| 56 | func TestT5RefusesANullArchiveVersionBeforeItsCache(t *testing.T) { |
| 57 | ctx := context.Background() |
| 58 | rec := provision.Record{Host: p1Host, Move: &provision.MoveState{ID: p1ID}} |
| 59 | good := moves.ArchiveRef{ManifestKey: "m.json", ManifestVersion: "mv1", SealedObjectKey: "s.sealed", SealedVersion: "sv1", Plain: "sha256:p"} |
| 60 | for name, mut := range map[string]func(*moves.ArchiveRef){ |
| 61 | "manifest": func(r *moves.ArchiveRef) { r.ManifestVersion = "null" }, |
| 62 | "sealed": func(r *moves.ArchiveRef) { r.SealedVersion = "null" }, |
| 63 | "both": func(r *moves.ArchiveRef) { r.ManifestVersion, r.SealedVersion = "null", "null" }, |
| 64 | "empty": func(r *moves.ArchiveRef) { r.SealedVersion = "" }, |
| 65 | } { |
| 66 | ref := good |
| 67 | mut(&ref) |
| 68 | w := &movesWorker{mirrors: map[string]lease.MirrorStore{}} |
| 69 | w.archives = map[string]verifiedArchive{p1ID: {ref: ref, check: moves.Check{OK: true}, plain: ref.Plain}} |
| 70 | got := w.checkArchive(ctx, rec, &moves.SourceReport{Archive: &ref}) |
| 71 | if got.check.OK || got.check.Reason != t5NotPinned { |
| 72 | t.Errorf("%s: T5 = %+v, want %q", name, got.check, t5NotPinned) |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | |